1 #include <msp/strings/format.h>
11 add_option("help", help, NO_ARG).set_help("Displays this help");
16 for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i)
20 GetOpt::OptionImpl &GetOpt::add_option(char s, const string &l, const Store &t, ArgType a)
23 throw invalid_argument("GetOpt::add_option");
24 if(t.is_list() && a!=REQUIRED_ARG)
25 throw invalid_argument("GetOpt::add_option");
27 for(OptionList::iterator i=opts.begin(); i!=opts.end(); )
29 if((s!=0 && (*i)->get_short()==s) || (*i)->get_long()==l)
38 opts.push_back(new OptionImpl(s, l, t, a));
42 GetOpt::OptionImpl &GetOpt::get_option(char s)
44 for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i)
45 if((*i)->get_short()==s)
47 throw usage_error(string("Unknown option -")+s);
50 GetOpt::OptionImpl &GetOpt::get_option(const string &l)
52 for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i)
53 if((*i)->get_long()==l)
55 throw usage_error(string("Unknown option --")+l);
58 void GetOpt::operator()(unsigned argc, const char *const *argv)
72 i += process_long(argv+i);
75 i += process_short(argv+i);
78 args.push_back(argv[i++]);
82 args.push_back(argv[i]);
84 catch(const usage_error &e)
86 throw usage_error(e.what(), "Usage: "+generate_usage(argv[0]));
90 throw usage_error(string("Help for ")+argv[0]+":", generate_help());
93 unsigned GetOpt::process_long(const char *const *argp)
96 const char *arg = argp[0]+2;
98 // See if the argument contains an =
100 for(; arg[equals] && arg[equals]!='='; ++equals) ;
102 OptionImpl &opt = get_option(string(arg, equals));
105 // Process the part after the = as option argument
106 opt.process(arg+equals+1);
107 else if(opt.get_arg_type()==REQUIRED_ARG)
110 throw usage_error("--"+string(arg)+" requires an argument");
112 // Process the next argument as option argument
113 opt.process(argp[1]);
122 unsigned GetOpt::process_short(const char *const *argp)
125 const char *arg = argp[0]+1;
127 // Loop through all characters in the argument
130 OptionImpl &opt = get_option(*arg);
132 if(arg[1] && opt.get_arg_type()!=NO_ARG)
134 // Need an option argument and we have characters left - use them
138 else if(opt.get_arg_type()==REQUIRED_ARG)
141 throw usage_error("-"+string(1, *arg)+" requires an argument");
143 // Use the next argument as option argument
144 opt.process(argp[1]);
154 string GetOpt::generate_usage(const string &argv0) const
156 string result = argv0;
157 for(OptionList::const_iterator i=opts.begin(); i!=opts.end(); ++i)
160 if((*i)->get_short())
162 result += format("-%c", (*i)->get_short());
163 if(!(*i)->get_long().empty())
165 else if((*i)->get_arg_type()==OPTIONAL_ARG)
166 result += format("[%s]", (*i)->get_metavar());
167 else if((*i)->get_arg_type()==REQUIRED_ARG)
168 result += format(" %s", (*i)->get_metavar());
170 if(!(*i)->get_long().empty())
172 result += format("--%s", (*i)->get_long());
174 if((*i)->get_arg_type()==OPTIONAL_ARG)
175 result += format("[=%s]", (*i)->get_metavar());
176 else if((*i)->get_arg_type()==REQUIRED_ARG)
177 result += format("=%s", (*i)->get_metavar());
185 string GetOpt::generate_help() const
187 bool any_short = false;
188 for(OptionList::const_iterator i=opts.begin(); (!any_short && i!=opts.end()); ++i)
189 any_short = (*i)->get_short();
191 string::size_type maxw = 0;
192 list<string> switches;
193 for(OptionList::const_iterator i=opts.begin(); i!=opts.end(); ++i)
196 if((*i)->get_short())
198 swtch += format("-%c", (*i)->get_short());
199 if(!(*i)->get_long().empty())
201 else if((*i)->get_arg_type()==OPTIONAL_ARG)
202 swtch += format("[%s]", (*i)->get_metavar());
203 else if((*i)->get_arg_type()==REQUIRED_ARG)
204 swtch += format(" %s", (*i)->get_metavar());
208 if(!(*i)->get_long().empty())
210 swtch += format("--%s", (*i)->get_long());
212 if((*i)->get_arg_type()==OPTIONAL_ARG)
213 swtch += format("[=%s]", (*i)->get_metavar());
214 else if((*i)->get_arg_type()==REQUIRED_ARG)
215 swtch += format("=%s", (*i)->get_metavar());
217 switches.push_back(swtch);
218 maxw = max(maxw, swtch.size());
222 list<string>::const_iterator j = switches.begin();
223 for(OptionList::const_iterator i=opts.begin(); i!=opts.end(); ++i, ++j)
224 result += format(" %s%s%s\n", *j, string(maxw+2-j->size(), ' '), (*i)->get_help());
230 GetOpt::OptionImpl::OptionImpl(char s, const std::string &l, const Store &t, ArgType a):
240 GetOpt::OptionImpl::~OptionImpl()
245 GetOpt::OptionImpl &GetOpt::OptionImpl::set_help(const string &h)
251 GetOpt::OptionImpl &GetOpt::OptionImpl::set_help(const string &h, const string &m)
258 GetOpt::OptionImpl &GetOpt::OptionImpl::bind_seen_count(unsigned &c)
264 void GetOpt::OptionImpl::process()
266 if(arg_type==REQUIRED_ARG)
267 throw usage_error("--"+lng+" requires an argument");
271 *ext_seen_count = seen_count;
277 catch(const exception &e)
279 throw usage_error("Invalid argument for --"+lng+" ("+e.what()+")");
283 void GetOpt::OptionImpl::process(const string &arg)
286 throw usage_error("--"+lng+" takes no argument");
290 *ext_seen_count = seen_count;
296 catch(const exception &e)
298 throw usage_error("Invalid argument for --"+lng+" ("+e.what()+")");