+string GetOpt::generate_usage(const string &argv0, bool compact) const
+{
+ string result = argv0;
+ if(compact)
+ result += " [options]";
+ else
+ {
+ for(const OptionImpl *o: opts)
+ {
+ result += " [";
+ if(o->get_short())
+ {
+ result += format("-%c", o->get_short());
+ if(!o->get_long().empty())
+ result += '|';
+ else if(o->get_arg_type()==OPTIONAL_ARG)
+ result += format("[%s]", o->get_metavar());
+ else if(o->get_arg_type()==REQUIRED_ARG)
+ result += format(" %s", o->get_metavar());
+ }
+ if(!o->get_long().empty())
+ {
+ result += format("--%s", o->get_long());
+
+ if(o->get_arg_type()==OPTIONAL_ARG)
+ result += format("[=%s]", o->get_metavar());
+ else if(o->get_arg_type()==REQUIRED_ARG)
+ result += format("=%s", o->get_metavar());
+ }
+ result += ']';
+ }
+ }
+
+ for(const ArgumentImpl *a: args)
+ {
+ result += ' ';
+ if(a->get_type()==OPTIONAL_ARG)
+ result += '[';
+ result += format("<%s>", a->get_name());
+ if(a->is_list_store())
+ result += " ...";
+ if(a->get_type()==OPTIONAL_ARG)
+ result += ']';
+ }
+
+ return result;
+}
+
+string GetOpt::generate_help() const
+{
+ bool any_short = any_of(opts.begin(), opts.end(), [](const OptionImpl *o){ return o->get_short(); });
+
+ string::size_type maxw = 0;
+ vector<string> switches;
+ for(const OptionImpl *o: opts)
+ {
+ string swtch;
+ if(o->get_short())
+ {
+ swtch += format("-%c", o->get_short());
+ if(!o->get_long().empty())
+ swtch += ", ";
+ else if(o->get_arg_type()==OPTIONAL_ARG)
+ swtch += format("[%s]", o->get_metavar());
+ else if(o->get_arg_type()==REQUIRED_ARG)
+ swtch += format(" %s", o->get_metavar());
+ }
+ else if(any_short)
+ swtch += " ";
+ if(!o->get_long().empty())
+ {
+ swtch += format("--%s", o->get_long());
+
+ if(o->get_arg_type()==OPTIONAL_ARG)
+ swtch += format("[=%s]", o->get_metavar());
+ else if(o->get_arg_type()==REQUIRED_ARG)
+ swtch += format("=%s", o->get_metavar());
+ }
+ switches.push_back(swtch);
+ maxw = max(maxw, swtch.size());
+ }
+
+ vector<string> pargs;
+ for(const ArgumentImpl *a: args)
+ {
+ string parg = format("<%s>", a->get_name());
+ pargs.push_back(parg);
+ maxw = max(maxw, parg.size());
+ }
+
+ string result;
+ result += "Options:\n";
+ auto j = switches.begin();
+ for(auto i=opts.begin(); i!=opts.end(); ++i, ++j)
+ result += format(" %s%s%s\n", *j, string(maxw+2-j->size(), ' '), (*i)->get_help());
+ if(!pargs.empty())
+ {
+ result += "\nArguments:\n";
+ j = pargs.begin();
+ for(auto i=args.begin(); i!=args.end(); ++i, ++j)
+ result += format(" %s%s%s\n", *j, string(maxw+2-j->size(), ' '), (*i)->get_help());
+ }
+
+ return result;
+}
+
+
+GetOpt::OptionImpl::OptionImpl(char s, const string &l, const Store &t, ArgType a):
+ shrt(s),
+ lng(l),
+ arg_type(a),
+ store(t.clone())
+{ }
+
+GetOpt::OptionImpl::~OptionImpl()
+{
+ delete store;
+}
+
+GetOpt::OptionImpl &GetOpt::OptionImpl::set_help(const string &h)
+{
+ help = h;
+ return *this;
+}
+
+GetOpt::OptionImpl &GetOpt::OptionImpl::set_help(const string &h, const string &m)
+{
+ help = h;
+ metavar = m;
+ return *this;
+}
+
+GetOpt::OptionImpl &GetOpt::OptionImpl::bind_seen_count(unsigned &c)
+{
+ ext_seen_count = &c;
+ return *this;
+}
+
+void GetOpt::OptionImpl::process()
+{
+ if(arg_type==REQUIRED_ARG)
+ throw usage_error("--"+lng+" requires an argument");
+
+ ++seen_count;
+ if(ext_seen_count)
+ *ext_seen_count = seen_count;
+
+ try
+ {
+ store->store();
+ }
+ catch(const exception &e)
+ {
+ throw usage_error("Invalid argument for --"+lng+" ("+e.what()+")");
+ }
+}
+
+void GetOpt::OptionImpl::process(const string &arg)
+{
+ if(arg_type==NO_ARG)
+ throw usage_error("--"+lng+" takes no argument");
+
+ ++seen_count;
+ if(ext_seen_count)
+ *ext_seen_count = seen_count;
+
+ try
+ {
+ store->store(arg);
+ }
+ catch(const exception &e)
+ {
+ throw usage_error("Invalid argument for --"+lng+" ("+e.what()+")");
+ }
+}
+
+
+GetOpt::ArgumentImpl::ArgumentImpl(const string &n, const Store &t, ArgType a):
+ name(n),
+ type(a),
+ store(t.clone())
+{ }
+
+GetOpt::ArgumentImpl::~ArgumentImpl()
+{
+ delete store;
+}
+
+GetOpt::ArgumentImpl &GetOpt::ArgumentImpl::set_help(const string &h)
+{
+ help = h;
+ return *this;
+}
+
+void GetOpt::ArgumentImpl::process(const string &arg)
+{
+ try
+ {
+ store->store(arg);
+ }
+ catch(const exception &e)
+ {
+ throw usage_error("Invalid "+name+" ("+e.what()+")");
+ }
+}
+