GeneticAlgoithm
Implementation of the genetic algorithm
optparse.h
Go to the documentation of this file.
1 /**
2  * @file
3  *
4  * @brief Copyright (C) 2010 Johannes Weißl <jargon@molb.org>
5  * License: your favourite BSD-style license
6  */
7 
8 #ifndef OPTPARSE_H
9 #define OPTPARSE_H
10 
11 #include <algorithm>
12 #include <cstdlib>
13 #include <ciso646>
14 #include <complex>
15 #include <iostream>
16 #include <list>
17 #include <map>
18 #include <set>
19 #include <sstream>
20 #include <stdexcept>
21 #include <string>
22 #include <vector>
23 
24 
25 namespace optparse
26 {
27  class Callback;
28  class Option;
29  class OptionGroup;
30  class OptionParser;
31 
32 
33  // Class for automatic conversion from string -> anytype.
34  class Value
35  {
36  public:
37 
38  Value() : str(), valid(false) {}
39 
40  explicit Value(const std::string &v) : str(v), valid(true) {}
41 
42  operator const char *()
43  {
44  return str.c_str();
45  }
46 
47  operator bool()
48  {
49  bool t;
50  return (valid && (std::istringstream(str) >> t)) ? t : false;
51  }
52 
53  operator short()
54  {
55  short t;
56  return (valid && (std::istringstream(str) >> t)) ? t : 0;
57  }
58 
59  operator unsigned short()
60  {
61  unsigned short t;
62  return (valid && (std::istringstream(str) >> t)) ? t : 0;
63  }
64 
65  operator int()
66  {
67  int t;
68  return (valid && (std::istringstream(str) >> t)) ? t : 0;
69  }
70 
71  operator unsigned int()
72  {
73  unsigned int t;
74  return (valid && (std::istringstream(str) >> t)) ? t : 0;
75  }
76 
77  operator long()
78  {
79  long t;
80  return (valid && (std::istringstream(str) >> t)) ? t : 0;
81  }
82 
83  operator unsigned long()
84  {
85  unsigned long t;
86  return (valid && (std::istringstream(str) >> t)) ? t : 0;
87  }
88 
89  operator float()
90  {
91  float t;
92  return (valid && (std::istringstream(str) >> t)) ? t : 0;
93  }
94 
95  operator double()
96  {
97  double t;
98  return (valid && (std::istringstream(str) >> t)) ? t : 0;
99  }
100 
101  operator long double()
102  {
103  long double t;
104  return (valid && (std::istringstream(str) >> t)) ? t : 0;
105  }
106 
107  operator std::string()
108  {
109  return str;
110  }
111 
112  private:
113 
114  const std::string str;
115  bool valid;
116  };
117 
118 
119  class Values
120  {
121  public:
122 
123  Values() : _map() {}
124 
125  const std::string &operator[](const std::string &d) const
126  {
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;
130  }
131 
132  std::string &operator[](const std::string &d)
133  {
134  return _map[d];
135  }
136 
137  bool is_set(const std::string &d) const
138  {
139  return _map.find(d) != _map.end();
140  }
141 
142  bool is_set_by_user(const std::string &d) const
143  {
144  return _user_set.find(d) != _user_set.end();
145  }
146 
147  void is_set_by_user(const std::string &d, bool yes)
148  {
149  if (yes)
150  {
151  _user_set.insert(d);
152  }
153  else
154  {
155  _user_set.erase(d);
156  }
157  }
158 
159  Value get(const std::string &d) const
160  {
161  return (is_set(d)) ? Value((*this)[d]) : Value();
162  }
163 
164  typedef std::vector<std::string>::iterator iterator;
165  typedef std::vector<std::string>::const_iterator const_iterator;
166 
167  std::vector<std::string> &all(const std::string &d)
168  {
169  return _append_map[d];
170  }
171 
172  const std::vector<std::string> all(const std::string &d) const
173  {
174  static const std::vector<std::string> empty;
175  return (_append_map.find(d) == _append_map.end()) ?
176  empty :
177  _append_map.at(d);
178  }
179 
180  private:
181 
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;
185  };
186 
187 
188  namespace detail
189  {
190  class str_wrap
191  {
192  public:
193 
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)
197  {
198  return lwrap + s + rwrap;
199  }
200 
201  const std::string lwrap, rwrap;
202  };
203 
204 
205  template<typename InputIterator, typename UnaryOperator>
206  static std::string str_join_trans(const std::string &sep, InputIterator begin, InputIterator end, UnaryOperator op)
207  {
208  std::string buf;
209  for (InputIterator it = begin; it != end; ++it)
210  {
211  if (it != begin)
212  {
213  buf += sep;
214  }
215  buf += op(*it);
216  }
217 
218  return buf;
219  }
220 
221 
222  template<class InputIterator>
223  static std::string str_join(const std::string &sep, InputIterator begin, InputIterator end)
224  {
225  return str_join_trans(sep, begin, end, str_wrap(""));
226  }
227 
228 
229  static std::string &str_replace_helper(std::string &s, const std::string &patt, const std::string &repl)
230  {
231  size_t pos = 0;
232  const size_t n = patt.length();
233  while (true)
234  {
235  pos = s.find(patt, pos);
236  if (pos == std::string::npos)
237  {
238  break;
239  }
240  s.replace(pos, n, repl);
241  pos += repl.size();
242  }
243 
244  return s;
245  }
246 
247 
248  static std::string str_replace(const std::string &s, const std::string &patt, const std::string &repl)
249  {
250  std::string tmp = s;
251  str_replace_helper(tmp, patt, repl);
252  return tmp;
253  }
254 
255 
256  static std::string str_format(const std::string &s, size_t pre, size_t len, bool indent_first = true)
257  {
258  std::stringstream ss;
259  std::string p;
260  if (indent_first)
261  {
262  p = std::string(pre, ' ');
263  }
264 
265  size_t pos = 0, linestart = 0;
266  size_t line = 0;
267  while (true)
268  {
269  bool wrap = false;
270 
271  size_t new_pos = s.find_first_of(" \n\t", pos);
272  if (new_pos == std::string::npos)
273  {
274  break;
275  }
276 
277  if (s[new_pos] == '\n')
278  {
279  pos = new_pos + 1;
280  wrap = true;
281  }
282 
283  if (line == 1)
284  {
285  p = std::string(pre, ' ');
286  }
287 
288  if (wrap or new_pos + pre > linestart + len)
289  {
290  ss << p << s.substr(linestart, pos - linestart - 1) << std::endl;
291  linestart = pos;
292  line++;
293  }
294 
295  pos = new_pos + 1;
296  }
297 
298  ss << p << s.substr(linestart) << std::endl;
299  return ss.str();
300  }
301 
302 
303  static std::string str_inc(const std::string &s)
304  {
305  std::stringstream ss;
306  long i = 0;
307  std::istringstream(s) >> i;
308  ss << i + 1;
309  return ss.str();
310  }
311 
312 
313  static unsigned int cols()
314  {
315  unsigned int n = 80;
316 #ifndef _WIN32
317  const char *s = getenv("COLUMNS");
318  if (s)
319  {
320  std::istringstream(s) >> n;
321  }
322 #endif
323  return n;
324  }
325 
326 
327  static std::string basename(const std::string &s)
328  {
329  std::string b = s;
330  size_t i = b.find_last_not_of('/');
331  if (i == std::string::npos)
332  {
333  if (b[0] == '/')
334  {
335  b.erase(1);
336  }
337 
338  return b;
339  }
340 
341  b.erase(i + 1, b.length() - i - 1);
342  i = b.find_last_of("/");
343  if (i != std::string::npos)
344  {
345  b.erase(0, i + 1);
346  }
347 
348  return b;
349  }
350 
351 
352  static OptionParser &add_option_group_helper(OptionParser &parser,
353  const OptionGroup &group);
354 
355 
356  static Values &parse_args_helper(OptionParser &parser,
357  const std::vector<std::string> &v);
358 
359 
360  static std::string format_help_helper(const OptionParser &parser);
361  }
362 
363 
364  class Callback
365  {
366  public:
367 
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() {}
373  };
374 
375 
376  class Option
377  {
378  public:
379 
380  Option() : _action("store"), _type("string"), _nargs(1), _suppress_help(false), _callback(0) {}
381 
382  Option &action(const std::string &a)
383  {
384  _action = a;
385  if (a == "store_const" or
386  a == "store_true" or
387  a == "store_false" or
388  a == "append_const" or
389  a == "count" or
390  a == "help" or
391  a == "version")
392  {
393  nargs(0);
394  }
395  return *this;
396  }
397 
398  Option &type(const std::string &t)
399  {
400  _type = t;
401  return *this;
402  }
403 
404  Option &dest(const std::string &d)
405  {
406  _dest = d;
407  return *this;
408  }
409 
410  Option &set_default(const std::string &d)
411  {
412  _default = d;
413  return *this;
414  }
415 
416  template<typename T>
417  Option &set_default(T t)
418  {
419  std::ostringstream ss;
420  ss << t;
421  _default = ss.str();
422  return *this;
423  }
424 
425  Option &nargs(size_t n)
426  {
427  // This doesn't seem to be currently supported.
428  if (n > 1)
429  {
430  throw std::invalid_argument(
431  "nargs greater than 1 not supported");
432  }
433 
434  _nargs = n;
435  return *this;
436  }
437 
438  Option &set_const(const std::string &c)
439  {
440  _const = c;
441  return *this;
442  }
443 
444  template<typename InputIterator>
445  Option &choices(InputIterator begin, InputIterator end)
446  {
447  _choices.assign(begin, end);
448  type("choice");
449  return *this;
450  }
451 
452  Option &help(const std::string &h)
453  {
454  _help = h;
455  return *this;
456  }
457 
458  Option &suppress_help(const bool suppress=true)
459  {
460  _suppress_help = suppress;
461  return *this;
462  }
463 
464  Option &metavar(const std::string &m)
465  {
466  _metavar = m;
467  return *this;
468  }
469 
470  Option &callback(Callback &c)
471  {
472  _callback = &c;
473  return *this;
474  }
475 
476  const std::string &action() const
477  {
478  return _action;
479  }
480 
481  const std::string &type() const
482  {
483  return _type;
484  }
485 
486  const std::string &dest() const
487  {
488  return _dest;
489  }
490 
491  const std::string &get_default() const
492  {
493  return _default;
494  }
495 
496  size_t nargs() const
497  {
498  return _nargs;
499  }
500 
501  const std::string &get_const() const
502  {
503  return _const;
504  }
505 
506  const std::list<std::string> &choices() const
507  {
508  return _choices;
509  }
510 
511  const std::string &help() const
512  {
513  return _help;
514  }
515 
516  const std::string &metavar() const
517  {
518  return _metavar;
519  }
520 
521  Callback *callback() const
522  {
523  return _callback;
524  }
525 
526  private:
527 
528  std::string check_type(const std::string &opt, const std::string &val) const
529  {
530  std::istringstream ss(val);
531  std::stringstream err;
532 
533  if (type() == "int" or type() == "long")
534  {
535  long t;
536  if (not (ss >> t))
537  {
538  err << "option" << " " << opt << ": " << "invalid integer value" << ": '" << val << "'";
539  }
540  }
541  else if (type() == "float" or type() == "double")
542  {
543  double t;
544  if (not (ss >> t))
545  {
546  err << "option" << " " << opt << ": " << "invalid floating-point value" << ": '" << val << "'";
547  }
548  }
549  else if (type() == "choice")
550  {
551  if (find(choices().begin(), choices().end(), val) == choices().end())
552  {
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()) << ")";
557  }
558  }
559  else if (type() == "complex")
560  {
561  std::complex<double> t;
562  if (not (ss >> t))
563  {
564  err << "option" << " " << opt << ": " << "invalid complex value" << ": '" << val << "'";
565  }
566  }
567 
568  return err.str();
569  }
570 
571  std::string format_option_help(const unsigned int indent=2) const
572  {
573  std::string mvar_short;
574  std::string mvar_long;
575 
576  if (nargs() == 1)
577  {
578  std::string mvar = metavar();
579  if (mvar == "")
580  {
581  mvar = type();
582  std::transform(mvar.begin(), mvar.end(), mvar.begin(), ::toupper);
583  }
584  mvar_short = " " + mvar;
585  mvar_long = "=" + mvar;
586  }
587 
588  std::stringstream ss;
589  ss << std::string(indent, ' ');
590 
591  if (not _short_opts.empty())
592  {
593  ss << detail::str_join_trans(", ", _short_opts.begin(), _short_opts.end(), detail::str_wrap("-", mvar_short));
594  if (not _long_opts.empty())
595  {
596  ss << ", ";
597  }
598  }
599  if (not _long_opts.empty())
600  {
601  ss << detail::str_join_trans(", ", _long_opts.begin(), _long_opts.end(), detail::str_wrap("--", mvar_long));
602  }
603 
604  return ss.str();
605  }
606 
607  std::string format_help(const unsigned int indent=2) const
608  {
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;
614  ss << h;
615 
616  // If the option list is too long, start a new paragraph.
617  if (h.length() >= (opt_width - 1))
618  {
619  ss << std::endl;
620  indent_first = true;
621  }
622  else
623  {
624  ss << std::string(opt_width - h.length(), ' ');
625  if (help() == "")
626  ss << std::endl;
627  }
628 
629  if (help() != "")
630  {
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);
633  }
634 
635  return ss.str();
636  }
637 
638  std::set<std::string> _short_opts;
639  std::set<std::string> _long_opts;
640 
641  std::string _action;
642  std::string _type;
643  std::string _dest;
644  std::string _default;
645  size_t _nargs;
646  std::string _const;
647  std::list<std::string> _choices;
648  std::string _help;
649  bool _suppress_help;
650  std::string _metavar;
651  Callback *_callback;
652 
653  friend class OptionParser;
654 
655  friend OptionParser &detail::add_option_group_helper(
656  OptionParser &parser,
657  const OptionGroup &group);
658  };
659 
660 
661  class OptionParser
662  {
663  public:
664 
665  OptionParser() :
666  _usage("%prog [options]"),
667  _add_help_option(true),
668  _add_version_option(true),
669  _interspersed_args(true)
670  {
671  }
672 
673 
674  OptionParser &usage(const std::string &u)
675  {
676  set_usage(u);
677  return *this;
678  }
679 
680  OptionParser &version(const std::string &v)
681  {
682  _version = v;
683  return *this;
684  }
685 
686  OptionParser &description(const std::string &d)
687  {
688  _description = d;
689  return *this;
690  }
691 
692  OptionParser &add_help_option(bool h)
693  {
694  _add_help_option = h;
695  return *this;
696  }
697 
698  OptionParser &add_version_option(bool v)
699  {
700  _add_version_option = v;
701  return *this;
702  }
703 
704  OptionParser &prog(const std::string &p)
705  {
706  _prog = p;
707  return *this;
708  }
709 
710  OptionParser &epilog(const std::string &e)
711  {
712  _epilog = e;
713  return *this;
714  }
715 
716  OptionParser &set_defaults(const std::string &dest, const std::string &val)
717  {
718  _defaults[dest] = val;
719  return *this;
720  }
721 
722  template<typename T>
723  OptionParser &set_defaults(const std::string &dest, T t)
724  {
725  std::ostringstream ss;
726  ss << t;
727  _defaults[dest] = ss.str();
728  return *this;
729  }
730 
731  OptionParser &enable_interspersed_args()
732  {
733  _interspersed_args = true;
734  return *this;
735  }
736 
737  OptionParser &disable_interspersed_args()
738  {
739  _interspersed_args = false;
740  return *this;
741  }
742 
743  OptionParser &add_option_group(const OptionGroup &group)
744  {
745  return detail::add_option_group_helper(*this, group);
746  }
747 
748  const std::string &usage() const
749  {
750  return _usage;
751  }
752 
753  const std::string &version() const
754  {
755  return _version;
756  }
757 
758  const std::string &description() const
759  {
760  return _description;
761  }
762 
763  bool add_help_option() const
764  {
765  return _add_help_option;
766  }
767 
768  bool add_version_option() const
769  {
770  return _add_version_option;
771  }
772 
773  const std::string &prog() const
774  {
775  return _prog;
776  }
777 
778  const std::string &epilog() const
779  {
780  return _epilog;
781  }
782 
783  bool interspersed_args() const
784  {
785  return _interspersed_args;
786  }
787 
788  Option &add_option(const std::vector<std::string> &opt)
789  {
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)
794  {
795  if (it->substr(0, 2) == "--")
796  {
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;
802  }
803  else
804  {
805  const std::string s = it->substr(1, 1);
806  if (dest_fallback == "")
807  dest_fallback = s;
808  option._short_opts.insert(s);
809  _optmap_s[s] = &option;
810  }
811  }
812  if (option.dest() == "")
813  {
814  option.dest(dest_fallback);
815  }
816  return option;
817  }
818 
819  Option &add_option(const std::string &opt)
820  {
821  const std::string tmp[1] = {opt};
822  return add_option(std::vector<std::string>(&tmp[0], &tmp[1]));
823  }
824 
825  Option &add_option(const std::string &opt1, const std::string &opt2)
826  {
827  const std::string tmp[2] = {opt1, opt2};
828  return add_option(std::vector<std::string>(&tmp[0], &tmp[2]));
829  }
830 
831  Option &add_option(const std::string &opt1, const std::string &opt2, const std::string &opt3)
832  {
833  const std::string tmp[3] = {opt1, opt2, opt3};
834  return add_option(std::vector<std::string>(&tmp[0], &tmp[3]));
835  }
836 
837  Values &parse_args(int argc, char const *const *argv)
838  {
839  if (prog() == "")
840  {
841  prog(detail::basename(argv[0]));
842  }
843  return parse_args(&argv[1], &argv[argc]);
844  }
845 
846  Values &parse_args(const std::vector<std::string> &arguments)
847  {
848  return detail::parse_args_helper(*this, arguments);
849  }
850 
851  template<typename InputIterator>
852  Values &parse_args(InputIterator begin, InputIterator end)
853  {
854  return parse_args(std::vector<std::string>(begin, end));
855  }
856 
857  const std::vector<std::string> &args() const
858  {
859  return _leftover;
860  }
861 
862  std::string format_help() const
863  {
864  return detail::format_help_helper(*this);
865  }
866 
867  std::string format_option_help(unsigned int indent=2) const
868  {
869  std::stringstream ss;
870 
871  if (_opts.empty())
872  {
873  return ss.str();
874  }
875 
876  for (std::list<Option>::const_iterator it = _opts.begin(); it != _opts.end(); ++it)
877  {
878  if (not it->_suppress_help)
879  {
880  ss << it->format_help(indent);
881  }
882  }
883 
884  return ss.str();
885  }
886 
887  void print_help() const
888  {
889  std::cout << format_help();
890  }
891 
892  void set_usage(const std::string &u)
893  {
894  std::string lower = u;
895  std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
896  if (lower.compare(0, 7, "usage: ") == 0)
897  {
898  _usage = u.substr(7);
899  }
900  else
901  {
902  _usage = u;
903  }
904  }
905 
906  std::string get_usage() const
907  {
908  return format_usage(detail::str_replace(usage(), "%prog", prog()));
909  }
910 
911  void print_usage(std::ostream &out) const
912  {
913  std::string u = get_usage();
914  if (u != "")
915  {
916  out << u << std::endl;
917  }
918  }
919 
920  void print_usage() const
921  {
922  print_usage(std::cout);
923  }
924 
925  std::string get_version() const
926  {
927  return detail::str_replace(_version, "%prog", prog());
928  }
929 
930  void print_version(std::ostream &out) const
931  {
932  out << get_version() << std::endl;
933  }
934 
935  void print_version() const
936  {
937  print_version(std::cout);
938  }
939 
940  void error(const std::string &msg) const
941  {
942  std::cout << prog() << ": " << "error" << ": " << msg << std::endl;
943  print_help();
944  exit();
945  }
946 
947  void exit() const
948  {
949  std::exit(2);
950  }
951 
952  private:
953 
954  const Option &lookup_short_opt(const std::string &opt) const
955  {
956  std::map<std::string, Option const *>::const_iterator it = _optmap_s.find(opt);
957  if (it == _optmap_s.end())
958  {
959  error("no such option" + std::string(": -") + opt);
960  }
961  return *it->second;
962  }
963 
964  const Option &lookup_long_opt(const std::string &opt) const
965  {
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)
968  {
969  if (it->first.compare(0, opt.length(), opt) == 0)
970  {
971  matching.push_back(it->first);
972  }
973  }
974  if (matching.size() > 1)
975  {
976  std::string x = detail::str_join(", ", matching.begin(), matching.end());
977  error("ambiguous option" + std::string(": --") + opt + " (" + x + "?)");
978  }
979  if (matching.size() == 0)
980  {
981  error("no such option" + std::string(": --") + opt);
982  }
983 
984  return *_optmap_l.find(matching.front())->second;
985  }
986 
987  void handle_short_opt(const std::string &opt, const std::string &arg)
988  {
989  _remaining.pop_front();
990  std::string value;
991 
992  const Option &option = lookup_short_opt(opt);
993  if (option._nargs == 1)
994  {
995  value = arg.substr(2);
996  if (value == "")
997  {
998  if (_remaining.empty())
999  {
1000  error("-" + opt + " " + "option requires an argument");
1001  }
1002  value = _remaining.front();
1003  _remaining.pop_front();
1004  }
1005  }
1006  else
1007  {
1008  if (arg.length() > 2)
1009  {
1010  _remaining.push_front(std::string("-") + arg.substr(2));
1011  }
1012  }
1013 
1014  process_opt(option, std::string("-") + opt, value);
1015  }
1016 
1017  void handle_long_opt(const std::string &optstr)
1018  {
1019  _remaining.pop_front();
1020  std::string opt;
1021  std::string value;
1022 
1023  size_t delim = optstr.find("=");
1024  if (delim != std::string::npos)
1025  {
1026  opt = optstr.substr(0, delim);
1027  value = optstr.substr(delim + 1);
1028  }
1029  else
1030  {
1031  opt = optstr;
1032  }
1033 
1034  const Option &option = lookup_long_opt(opt);
1035  if (option._nargs == 1 and delim == std::string::npos)
1036  {
1037  if (not _remaining.empty())
1038  {
1039  value = _remaining.front();
1040  _remaining.pop_front();
1041  }
1042  }
1043 
1044  if (option._nargs == 1 and value == "")
1045  {
1046  error("--" + opt + " " + "option requires an argument");
1047  }
1048 
1049  process_opt(option, std::string("--") + opt, value);
1050  }
1051 
1052  void process_opt(const Option &o, const std::string &opt, const std::string &value)
1053  {
1054  if (o.action() == "store")
1055  {
1056  std::string err = o.check_type(opt, value);
1057  if (err != "")
1058  {
1059  error(err);
1060  }
1061  _values[o.dest()] = value;
1062  _values.is_set_by_user(o.dest(), true);
1063  }
1064  else if (o.action() == "store_const")
1065  {
1066  _values[o.dest()] = o.get_const();
1067  _values.is_set_by_user(o.dest(), true);
1068  }
1069  else if (o.action() == "store_true")
1070  {
1071  _values[o.dest()] = "1";
1072  _values.is_set_by_user(o.dest(), true);
1073  }
1074  else if (o.action() == "store_false")
1075  {
1076  _values[o.dest()] = "0";
1077  _values.is_set_by_user(o.dest(), true);
1078  }
1079  else if (o.action() == "append")
1080  {
1081  std::string err = o.check_type(opt, value);
1082  if (err != "")
1083  {
1084  error(err);
1085  }
1086  _values[o.dest()] = value;
1087  _values.all(o.dest()).push_back(value);
1088  _values.is_set_by_user(o.dest(), true);
1089  }
1090  else if (o.action() == "append_const")
1091  {
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);
1095  }
1096  else if (o.action() == "count")
1097  {
1098  _values[o.dest()] = detail::str_inc(_values[o.dest()]);
1099  _values.is_set_by_user(o.dest(), true);
1100  }
1101  else if (o.action() == "help")
1102  {
1103  print_help();
1104  std::exit(0);
1105  }
1106  else if (o.action() == "version")
1107  {
1108  print_version();
1109  std::exit(0);
1110  }
1111  else if (o.action() == "callback" and o.callback())
1112  {
1113  (*o.callback())(o, opt, value, *this);
1114  }
1115  }
1116 
1117  std::string format_usage(const std::string &u) const
1118  {
1119  std::stringstream ss;
1120  ss << "Usage" << ": " << u << std::endl;
1121  return ss.str();
1122  }
1123 
1124  std::string _usage;
1125  std::string _version;
1126  std::string _description;
1127  bool _add_help_option;
1128  bool _add_version_option;
1129  std::string _prog;
1130  std::string _epilog;
1131  bool _interspersed_args;
1132 
1133  Values _values;
1134 
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;
1140 
1141  std::list<std::string> _remaining;
1142  std::vector<std::string> _leftover;
1143 
1144  friend OptionParser &detail::add_option_group_helper(
1145  OptionParser &parser,
1146  const OptionGroup &group);
1147 
1148  friend Values &detail::parse_args_helper(
1149  OptionParser &parser,
1150  const std::vector<std::string> &v);
1151 
1152  friend std::string detail::format_help_helper(const OptionParser &parser);
1153  };
1154 
1155 
1156  class OptionGroup : public OptionParser
1157  {
1158  public:
1159 
1160  OptionGroup(const std::string &t, const std::string &d="") :
1161  _title(t), _group_description(d) {}
1162 
1163  OptionGroup &title(const std::string &t)
1164  {
1165  _title = t;
1166  return *this;
1167  }
1168 
1169  OptionGroup &group_description(const std::string &d)
1170  {
1171  _group_description = d;
1172  return *this;
1173  }
1174 
1175  const std::string &title() const
1176  {
1177  return _title;
1178  }
1179 
1180  const std::string &group_description() const
1181  {
1182  return _group_description;
1183  }
1184 
1185  private:
1186 
1187  std::string _title;
1188  std::string _group_description;
1189  };
1190 
1191 
1192  namespace detail
1193  {
1194  static OptionParser &add_option_group_helper(OptionParser &parser,
1195  const OptionGroup &group)
1196  {
1197  for (std::list<Option>::const_iterator oit = group._opts.begin(); oit != group._opts.end(); ++oit)
1198  {
1199  const Option &option = *oit;
1200  for (std::set<std::string>::const_iterator it = option._short_opts.begin();
1201  it != option._short_opts.end();
1202  ++it)
1203  {
1204  parser._optmap_s[*it] = &option;
1205  }
1206 
1207  for (std::set<std::string>::const_iterator it = option._long_opts.begin();
1208  it != option._long_opts.end();
1209  ++it)
1210  {
1211  parser._optmap_l[*it] = &option;
1212  }
1213  }
1214  parser._groups.push_back(&group);
1215  return parser;
1216  }
1217 
1218 
1219  static Values &parse_args_helper(OptionParser &parser,
1220  const std::vector<std::string> &v)
1221  {
1222  parser._remaining.assign(v.begin(), v.end());
1223 
1224  if (parser.add_version_option() and parser.version() != "")
1225  {
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()));
1228  }
1229  if (parser.add_help_option())
1230  {
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()));
1233  }
1234 
1235  while (not parser._remaining.empty())
1236  {
1237  const std::string arg = parser._remaining.front();
1238 
1239  if (arg == "--")
1240  {
1241  parser._remaining.pop_front();
1242  break;
1243  }
1244 
1245  if (arg.substr(0, 2) == "--")
1246  {
1247  parser.handle_long_opt(arg.substr(2));
1248  }
1249  else if (arg.substr(0, 1) == "-" and arg.length() > 1)
1250  {
1251  parser.handle_short_opt(arg.substr(1, 1), arg);
1252  }
1253  else
1254  {
1255  parser._remaining.pop_front();
1256  parser._leftover.push_back(arg);
1257  if (not parser.interspersed_args())
1258  {
1259  break;
1260  }
1261  }
1262  }
1263  while (not parser._remaining.empty())
1264  {
1265  const std::string arg = parser._remaining.front();
1266  parser._remaining.pop_front();
1267  parser._leftover.push_back(arg);
1268  }
1269 
1270  for (std::map<std::string, std::string>::const_iterator it = parser._defaults.begin(); it != parser._defaults.end(); ++it)
1271  {
1272  if (not parser._values.is_set(it->first))
1273  {
1274  parser._values[it->first] = it->second;
1275  }
1276  }
1277 
1278  for (std::list<Option>::const_iterator it = parser._opts.begin(); it != parser._opts.end(); ++it)
1279  {
1280  if (it->get_default() != "" and not parser._values.is_set(it->dest()))
1281  {
1282  parser._values[it->dest()] = it->get_default();
1283  }
1284  }
1285 
1286  for (std::vector<OptionGroup const *>::iterator group_it = parser._groups.begin(); group_it != parser._groups.end(); ++group_it)
1287  {
1288  for (std::map<std::string, std::string>::const_iterator it = (*group_it)->_defaults.begin(); it != (*group_it)->_defaults.end(); ++it)
1289  {
1290  if (not parser._values.is_set(it->first))
1291  {
1292  parser._values[it->first] = it->second;;
1293  }
1294  }
1295 
1296  for (std::list<Option>::const_iterator it = (*group_it)->_opts.begin(); it != (*group_it)->_opts.end(); ++it)
1297  {
1298  if (it->get_default() != "" and not parser._values.is_set(it->dest()))
1299  {
1300  parser._values[it->dest()] = it->get_default();
1301  }
1302  }
1303  }
1304 
1305  return parser._values;
1306  }
1307 
1308 
1309  static std::string format_help_helper(const OptionParser &parser)
1310  {
1311  std::stringstream ss;
1312 
1313  ss << parser.get_usage() << std::endl;
1314 
1315  if (parser.description() != "")
1316  {
1317  ss << detail::str_format(parser.description(), 0, detail::cols()) << std::endl;
1318  }
1319 
1320  ss << "Options" << ":" << std::endl;
1321  ss << parser.format_option_help();
1322 
1323  for (std::vector<OptionGroup const *>::const_iterator it = parser._groups.begin();
1324  it != parser._groups.end();
1325  ++it)
1326  {
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);
1332  }
1333 
1334  if (parser.epilog() != "")
1335  {
1336  ss << std::endl << detail::str_format(parser.epilog(), 0, detail::cols());
1337  }
1338 
1339  return ss.str();
1340  }
1341  }
1342 }
1343 
1344 typedef optparse::Values Config;
1345 #endif