38 Value() : str(), valid(false) {}
40 explicit Value(
const std::string &v) : str(v), valid(true) {}
42 operator const char *()
50 return (valid && (std::istringstream(str) >> t)) ? t :
false;
56 return (valid && (std::istringstream(str) >> t)) ? t : 0;
59 operator unsigned short()
62 return (valid && (std::istringstream(str) >> t)) ? t : 0;
68 return (valid && (std::istringstream(str) >> t)) ? t : 0;
71 operator unsigned int()
74 return (valid && (std::istringstream(str) >> t)) ? t : 0;
80 return (valid && (std::istringstream(str) >> t)) ? t : 0;
83 operator unsigned long()
86 return (valid && (std::istringstream(str) >> t)) ? t : 0;
92 return (valid && (std::istringstream(str) >> t)) ? t : 0;
98 return (valid && (std::istringstream(str) >> t)) ? t : 0;
101 operator long double()
104 return (valid && (std::istringstream(str) >> t)) ? t : 0;
107 operator std::string()
114 const std::string str;
125 const std::string &operator[](
const std::string &d)
const 127 std::map<std::string, std::string>::const_iterator it = _map.find(d);
128 static const std::string empty =
"";
129 return (it != _map.end()) ? it->second : empty;
132 std::string &operator[](
const std::string &d)
137 bool is_set(
const std::string &d)
const 139 return _map.find(d) != _map.end();
142 bool is_set_by_user(
const std::string &d)
const 144 return _user_set.find(d) != _user_set.end();
147 void is_set_by_user(
const std::string &d,
bool yes)
159 Value
get(
const std::string &d)
const 161 return (is_set(d)) ? Value((*
this)[d]) : Value();
164 typedef std::vector<std::string>::iterator iterator;
165 typedef std::vector<std::string>::const_iterator const_iterator;
167 std::vector<std::string> &all(
const std::string &d)
169 return _append_map[d];
172 const std::vector<std::string> all(
const std::string &d)
const 174 static const std::vector<std::string> empty;
175 return (_append_map.find(d) == _append_map.end()) ?
182 std::map<std::string, std::string> _map;
183 std::map<std::string, std::vector<std::string> > _append_map;
184 std::set<std::string> _user_set;
194 str_wrap(
const std::string &l,
const std::string &r) : lwrap(l), rwrap(r) {}
195 explicit str_wrap(
const std::string &w) : lwrap(w), rwrap(w) {}
196 std::string operator()(
const std::string &s)
198 return lwrap + s + rwrap;
201 const std::string lwrap, rwrap;
205 template<
typename InputIterator,
typename UnaryOperator>
206 static std::string str_join_trans(
const std::string &sep, InputIterator begin, InputIterator end, UnaryOperator op)
209 for (InputIterator it = begin; it != end; ++it)
222 template<
class InputIterator>
223 static std::string str_join(
const std::string &sep, InputIterator begin, InputIterator end)
225 return str_join_trans(sep, begin, end, str_wrap(
""));
229 static std::string &str_replace_helper(std::string &s,
const std::string &patt,
const std::string &repl)
232 const size_t n = patt.length();
235 pos = s.find(patt, pos);
236 if (pos == std::string::npos)
240 s.replace(pos, n, repl);
248 static std::string str_replace(
const std::string &s,
const std::string &patt,
const std::string &repl)
251 str_replace_helper(tmp, patt, repl);
256 static std::string str_format(
const std::string &s,
size_t pre,
size_t len,
bool indent_first =
true)
258 std::stringstream ss;
262 p = std::string(pre,
' ');
265 size_t pos = 0, linestart = 0;
271 size_t new_pos = s.find_first_of(
" \n\t", pos);
272 if (new_pos == std::string::npos)
277 if (s[new_pos] ==
'\n')
285 p = std::string(pre,
' ');
288 if (wrap or new_pos + pre > linestart + len)
290 ss << p << s.substr(linestart, pos - linestart - 1) << std::endl;
298 ss << p << s.substr(linestart) << std::endl;
303 static std::string str_inc(
const std::string &s)
305 std::stringstream ss;
307 std::istringstream(s) >> i;
313 static unsigned int cols()
317 const char *s = getenv(
"COLUMNS");
320 std::istringstream(s) >> n;
327 static std::string basename(
const std::string &s)
330 size_t i = b.find_last_not_of(
'/');
331 if (i == std::string::npos)
341 b.erase(i + 1, b.length() - i - 1);
342 i = b.find_last_of(
"/");
343 if (i != std::string::npos)
352 static OptionParser &add_option_group_helper(OptionParser &parser,
353 const OptionGroup &group);
356 static Values &parse_args_helper(OptionParser &parser,
357 const std::vector<std::string> &v);
360 static std::string format_help_helper(
const OptionParser &parser);
368 virtual void operator()(
const Option &option,
369 const std::string &opt,
370 const std::string &val,
371 const OptionParser &parser) = 0;
372 virtual ~Callback() {}
380 Option() : _action(
"store"), _type(
"string"), _nargs(1), _suppress_help(false), _callback(0) {}
382 Option &action(
const std::string &a)
385 if (a ==
"store_const" or
387 a ==
"store_false" or
388 a ==
"append_const" or
398 Option &type(
const std::string &t)
404 Option &dest(
const std::string &d)
410 Option &set_default(
const std::string &d)
417 Option &set_default(T t)
419 std::ostringstream ss;
425 Option &nargs(
size_t n)
430 throw std::invalid_argument(
431 "nargs greater than 1 not supported");
438 Option &set_const(
const std::string &c)
444 template<
typename InputIterator>
445 Option &choices(InputIterator begin, InputIterator end)
447 _choices.assign(begin, end);
452 Option &help(
const std::string &h)
458 Option &suppress_help(
const bool suppress=
true)
460 _suppress_help = suppress;
464 Option &metavar(
const std::string &m)
470 Option &callback(Callback &c)
476 const std::string &action()
const 481 const std::string &type()
const 486 const std::string &dest()
const 491 const std::string &get_default()
const 501 const std::string &get_const()
const 506 const std::list<std::string> &choices()
const 511 const std::string &help()
const 516 const std::string &metavar()
const 521 Callback *callback()
const 528 std::string check_type(
const std::string &opt,
const std::string &val)
const 530 std::istringstream ss(val);
531 std::stringstream err;
533 if (type() ==
"int" or type() ==
"long")
538 err <<
"option" <<
" " << opt <<
": " <<
"invalid integer value" <<
": '" << val <<
"'";
541 else if (type() ==
"float" or type() ==
"double")
546 err <<
"option" <<
" " << opt <<
": " <<
"invalid floating-point value" <<
": '" << val <<
"'";
549 else if (type() ==
"choice")
551 if (find(choices().begin(), choices().end(), val) == choices().end())
553 std::list<std::string> tmp = choices();
554 std::transform(tmp.begin(), tmp.end(), tmp.begin(), detail::str_wrap(
"'"));
555 err <<
"option" <<
" " << opt <<
": " <<
"invalid choice" <<
": '" << val <<
"'" 556 <<
" (" <<
"choose from" <<
" " << detail::str_join(
", ", tmp.begin(), tmp.end()) <<
")";
559 else if (type() ==
"complex")
561 std::complex<double> t;
564 err <<
"option" <<
" " << opt <<
": " <<
"invalid complex value" <<
": '" << val <<
"'";
571 std::string format_option_help(
const unsigned int indent=2)
const 573 std::string mvar_short;
574 std::string mvar_long;
578 std::string mvar = metavar();
582 std::transform(mvar.begin(), mvar.end(), mvar.begin(), ::toupper);
584 mvar_short =
" " + mvar;
585 mvar_long =
"=" + mvar;
588 std::stringstream ss;
589 ss << std::string(indent,
' ');
591 if (not _short_opts.empty())
593 ss << detail::str_join_trans(
", ", _short_opts.begin(), _short_opts.end(), detail::str_wrap(
"-", mvar_short));
594 if (not _long_opts.empty())
599 if (not _long_opts.empty())
601 ss << detail::str_join_trans(
", ", _long_opts.begin(), _long_opts.end(), detail::str_wrap(
"--", mvar_long));
607 std::string format_help(
const unsigned int indent=2)
const 609 std::stringstream ss;
610 std::string h = format_option_help(indent);
611 unsigned int width = detail::cols();
612 unsigned int opt_width = std::min(width * 3 / 10, 36u);
613 bool indent_first =
false;
617 if (h.length() >= (opt_width - 1))
624 ss << std::string(opt_width - h.length(),
' ');
631 std::string help_str = (get_default() !=
"") ? detail::str_replace(help(),
"%default", get_default()) : help();
632 ss << detail::str_format(help_str, opt_width, width, indent_first);
638 std::set<std::string> _short_opts;
639 std::set<std::string> _long_opts;
644 std::string _default;
647 std::list<std::string> _choices;
650 std::string _metavar;
653 friend class OptionParser;
655 friend OptionParser &detail::add_option_group_helper(
656 OptionParser &parser,
657 const OptionGroup &group);
666 _usage(
"%prog [options]"),
667 _add_help_option(true),
668 _add_version_option(true),
669 _interspersed_args(true)
674 OptionParser &usage(
const std::string &u)
680 OptionParser &version(
const std::string &v)
686 OptionParser &description(
const std::string &d)
692 OptionParser &add_help_option(
bool h)
694 _add_help_option = h;
698 OptionParser &add_version_option(
bool v)
700 _add_version_option = v;
704 OptionParser &prog(
const std::string &p)
710 OptionParser &epilog(
const std::string &e)
716 OptionParser &set_defaults(
const std::string &dest,
const std::string &val)
718 _defaults[dest] = val;
723 OptionParser &set_defaults(
const std::string &dest, T t)
725 std::ostringstream ss;
727 _defaults[dest] = ss.str();
731 OptionParser &enable_interspersed_args()
733 _interspersed_args =
true;
737 OptionParser &disable_interspersed_args()
739 _interspersed_args =
false;
743 OptionParser &add_option_group(
const OptionGroup &group)
745 return detail::add_option_group_helper(*
this, group);
748 const std::string &usage()
const 753 const std::string &version()
const 758 const std::string &description()
const 763 bool add_help_option()
const 765 return _add_help_option;
768 bool add_version_option()
const 770 return _add_version_option;
773 const std::string &prog()
const 778 const std::string &epilog()
const 783 bool interspersed_args()
const 785 return _interspersed_args;
788 Option &add_option(
const std::vector<std::string> &opt)
790 _opts.resize(_opts.size() + 1);
791 Option &option = _opts.back();
792 std::string dest_fallback;
793 for (std::vector<std::string>::const_iterator it = opt.begin(); it != opt.end(); ++it)
795 if (it->substr(0, 2) ==
"--")
797 const std::string s = it->substr(2);
798 if (option.dest() ==
"")
799 option.dest(detail::str_replace(s,
"-",
"_"));
800 option._long_opts.insert(s);
801 _optmap_l[s] = &option;
805 const std::string s = it->substr(1, 1);
806 if (dest_fallback ==
"")
808 option._short_opts.insert(s);
809 _optmap_s[s] = &option;
812 if (option.dest() ==
"")
814 option.dest(dest_fallback);
819 Option &add_option(
const std::string &opt)
821 const std::string tmp[1] = {opt};
822 return add_option(std::vector<std::string>(&tmp[0], &tmp[1]));
825 Option &add_option(
const std::string &opt1,
const std::string &opt2)
827 const std::string tmp[2] = {opt1, opt2};
828 return add_option(std::vector<std::string>(&tmp[0], &tmp[2]));
831 Option &add_option(
const std::string &opt1,
const std::string &opt2,
const std::string &opt3)
833 const std::string tmp[3] = {opt1, opt2, opt3};
834 return add_option(std::vector<std::string>(&tmp[0], &tmp[3]));
837 Values &parse_args(
int argc,
char const *
const *argv)
841 prog(detail::basename(argv[0]));
843 return parse_args(&argv[1], &argv[argc]);
846 Values &parse_args(
const std::vector<std::string> &arguments)
848 return detail::parse_args_helper(*
this, arguments);
851 template<
typename InputIterator>
852 Values &parse_args(InputIterator begin, InputIterator end)
854 return parse_args(std::vector<std::string>(begin, end));
857 const std::vector<std::string> &args()
const 862 std::string format_help()
const 864 return detail::format_help_helper(*
this);
867 std::string format_option_help(
unsigned int indent=2)
const 869 std::stringstream ss;
876 for (std::list<Option>::const_iterator it = _opts.begin(); it != _opts.end(); ++it)
878 if (not it->_suppress_help)
880 ss << it->format_help(indent);
887 void print_help()
const 889 std::cout << format_help();
892 void set_usage(
const std::string &u)
894 std::string lower = u;
895 std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
896 if (lower.compare(0, 7,
"usage: ") == 0)
898 _usage = u.substr(7);
906 std::string get_usage()
const 908 return format_usage(detail::str_replace(usage(),
"%prog", prog()));
911 void print_usage(std::ostream &out)
const 913 std::string u = get_usage();
916 out << u << std::endl;
920 void print_usage()
const 922 print_usage(std::cout);
925 std::string get_version()
const 927 return detail::str_replace(_version,
"%prog", prog());
930 void print_version(std::ostream &out)
const 932 out << get_version() << std::endl;
935 void print_version()
const 937 print_version(std::cout);
940 void error(
const std::string &msg)
const 942 std::cout << prog() <<
": " <<
"error" <<
": " << msg << std::endl;
954 const Option &lookup_short_opt(
const std::string &opt)
const 956 std::map<std::string, Option const *>::const_iterator it = _optmap_s.find(opt);
957 if (it == _optmap_s.end())
959 error(
"no such option" + std::string(
": -") + opt);
964 const Option &lookup_long_opt(
const std::string &opt)
const 966 std::vector<std::string> matching;
967 for (std::map<std::string, Option const *>::const_iterator it = _optmap_l.begin(); it != _optmap_l.end(); ++it)
969 if (it->first.compare(0, opt.length(), opt) == 0)
971 matching.push_back(it->first);
974 if (matching.size() > 1)
976 std::string x = detail::str_join(
", ", matching.begin(), matching.end());
977 error(
"ambiguous option" + std::string(
": --") + opt +
" (" + x +
"?)");
979 if (matching.size() == 0)
981 error(
"no such option" + std::string(
": --") + opt);
984 return *_optmap_l.find(matching.front())->second;
987 void handle_short_opt(
const std::string &opt,
const std::string &arg)
989 _remaining.pop_front();
992 const Option &option = lookup_short_opt(opt);
993 if (option._nargs == 1)
995 value = arg.substr(2);
998 if (_remaining.empty())
1000 error(
"-" + opt +
" " +
"option requires an argument");
1002 value = _remaining.front();
1003 _remaining.pop_front();
1008 if (arg.length() > 2)
1010 _remaining.push_front(std::string(
"-") + arg.substr(2));
1014 process_opt(option, std::string(
"-") + opt, value);
1017 void handle_long_opt(
const std::string &optstr)
1019 _remaining.pop_front();
1023 size_t delim = optstr.find(
"=");
1024 if (delim != std::string::npos)
1026 opt = optstr.substr(0, delim);
1027 value = optstr.substr(delim + 1);
1034 const Option &option = lookup_long_opt(opt);
1035 if (option._nargs == 1 and delim == std::string::npos)
1037 if (not _remaining.empty())
1039 value = _remaining.front();
1040 _remaining.pop_front();
1044 if (option._nargs == 1 and value ==
"")
1046 error(
"--" + opt +
" " +
"option requires an argument");
1049 process_opt(option, std::string(
"--") + opt, value);
1052 void process_opt(
const Option &o,
const std::string &opt,
const std::string &value)
1054 if (o.action() ==
"store")
1056 std::string err = o.check_type(opt, value);
1061 _values[o.dest()] = value;
1062 _values.is_set_by_user(o.dest(),
true);
1064 else if (o.action() ==
"store_const")
1066 _values[o.dest()] = o.get_const();
1067 _values.is_set_by_user(o.dest(),
true);
1069 else if (o.action() ==
"store_true")
1071 _values[o.dest()] =
"1";
1072 _values.is_set_by_user(o.dest(),
true);
1074 else if (o.action() ==
"store_false")
1076 _values[o.dest()] =
"0";
1077 _values.is_set_by_user(o.dest(),
true);
1079 else if (o.action() ==
"append")
1081 std::string err = o.check_type(opt, value);
1086 _values[o.dest()] = value;
1087 _values.all(o.dest()).push_back(value);
1088 _values.is_set_by_user(o.dest(),
true);
1090 else if (o.action() ==
"append_const")
1092 _values[o.dest()] = o.get_const();
1093 _values.all(o.dest()).push_back(o.get_const());
1094 _values.is_set_by_user(o.dest(),
true);
1096 else if (o.action() ==
"count")
1098 _values[o.dest()] = detail::str_inc(_values[o.dest()]);
1099 _values.is_set_by_user(o.dest(),
true);
1101 else if (o.action() ==
"help")
1106 else if (o.action() ==
"version")
1111 else if (o.action() ==
"callback" and o.callback())
1113 (*o.callback())(o, opt, value, *
this);
1117 std::string format_usage(
const std::string &u)
const 1119 std::stringstream ss;
1120 ss <<
"Usage" <<
": " << u << std::endl;
1125 std::string _version;
1126 std::string _description;
1127 bool _add_help_option;
1128 bool _add_version_option;
1130 std::string _epilog;
1131 bool _interspersed_args;
1135 std::list<Option> _opts;
1136 std::map<std::string, Option const *> _optmap_s;
1137 std::map<std::string, Option const *> _optmap_l;
1138 std::map<std::string, std::string> _defaults;
1139 std::vector<OptionGroup const *> _groups;
1141 std::list<std::string> _remaining;
1142 std::vector<std::string> _leftover;
1144 friend OptionParser &detail::add_option_group_helper(
1145 OptionParser &parser,
1146 const OptionGroup &group);
1148 friend Values &detail::parse_args_helper(
1149 OptionParser &parser,
1150 const std::vector<std::string> &v);
1152 friend std::string detail::format_help_helper(
const OptionParser &parser);
1156 class OptionGroup :
public OptionParser
1160 OptionGroup(
const std::string &t,
const std::string &d=
"") :
1161 _title(t), _group_description(d) {}
1163 OptionGroup &title(
const std::string &t)
1169 OptionGroup &group_description(
const std::string &d)
1171 _group_description = d;
1175 const std::string &title()
const 1180 const std::string &group_description()
const 1182 return _group_description;
1188 std::string _group_description;
1194 static OptionParser &add_option_group_helper(OptionParser &parser,
1195 const OptionGroup &group)
1197 for (std::list<Option>::const_iterator oit = group._opts.begin(); oit != group._opts.end(); ++oit)
1199 const Option &option = *oit;
1200 for (std::set<std::string>::const_iterator it = option._short_opts.begin();
1201 it != option._short_opts.end();
1204 parser._optmap_s[*it] = &option;
1207 for (std::set<std::string>::const_iterator it = option._long_opts.begin();
1208 it != option._long_opts.end();
1211 parser._optmap_l[*it] = &option;
1214 parser._groups.push_back(&group);
1219 static Values &parse_args_helper(OptionParser &parser,
1220 const std::vector<std::string> &v)
1222 parser._remaining.assign(v.begin(), v.end());
1224 if (parser.add_version_option() and parser.version() !=
"")
1226 parser.add_option(
"--version").action(
"version").help(
"show program's version number and exit");
1227 parser._opts.splice(parser._opts.begin(), parser._opts, --(parser._opts.end()));
1229 if (parser.add_help_option())
1231 parser.add_option(
"-h",
"--help").action(
"help").help(
"show this help message and exit");
1232 parser._opts.splice(parser._opts.begin(), parser._opts, --(parser._opts.end()));
1235 while (not parser._remaining.empty())
1237 const std::string arg = parser._remaining.front();
1241 parser._remaining.pop_front();
1245 if (arg.substr(0, 2) ==
"--")
1247 parser.handle_long_opt(arg.substr(2));
1249 else if (arg.substr(0, 1) ==
"-" and arg.length() > 1)
1251 parser.handle_short_opt(arg.substr(1, 1), arg);
1255 parser._remaining.pop_front();
1256 parser._leftover.push_back(arg);
1257 if (not parser.interspersed_args())
1263 while (not parser._remaining.empty())
1265 const std::string arg = parser._remaining.front();
1266 parser._remaining.pop_front();
1267 parser._leftover.push_back(arg);
1270 for (std::map<std::string, std::string>::const_iterator it = parser._defaults.begin(); it != parser._defaults.end(); ++it)
1272 if (not parser._values.is_set(it->first))
1274 parser._values[it->first] = it->second;
1278 for (std::list<Option>::const_iterator it = parser._opts.begin(); it != parser._opts.end(); ++it)
1280 if (it->get_default() !=
"" and not parser._values.is_set(it->dest()))
1282 parser._values[it->dest()] = it->get_default();
1286 for (std::vector<OptionGroup const *>::iterator group_it = parser._groups.begin(); group_it != parser._groups.end(); ++group_it)
1288 for (std::map<std::string, std::string>::const_iterator it = (*group_it)->_defaults.begin(); it != (*group_it)->_defaults.end(); ++it)
1290 if (not parser._values.is_set(it->first))
1292 parser._values[it->first] = it->second;;
1296 for (std::list<Option>::const_iterator it = (*group_it)->_opts.begin(); it != (*group_it)->_opts.end(); ++it)
1298 if (it->get_default() !=
"" and not parser._values.is_set(it->dest()))
1300 parser._values[it->dest()] = it->get_default();
1305 return parser._values;
1309 static std::string format_help_helper(
const OptionParser &parser)
1311 std::stringstream ss;
1313 ss << parser.get_usage() << std::endl;
1315 if (parser.description() !=
"")
1317 ss << detail::str_format(parser.description(), 0, detail::cols()) << std::endl;
1320 ss <<
"Options" <<
":" << std::endl;
1321 ss << parser.format_option_help();
1323 for (std::vector<OptionGroup const *>::const_iterator it = parser._groups.begin();
1324 it != parser._groups.end();
1327 const OptionGroup &group = **it;
1328 ss << std::endl <<
" " << group.title() <<
":" << std::endl;
1329 if (group.group_description() !=
"")
1330 ss << detail::str_format(group.group_description(), 4, detail::cols()) << std::endl;
1331 ss << group.format_option_help(4);
1334 if (parser.epilog() !=
"")
1336 ss << std::endl << detail::str_format(parser.epilog(), 0, detail::cols());
1344 typedef optparse::Values Config;