CMS 3D CMS Logo

cxxopts.h
Go to the documentation of this file.
1 /*
2 
3 Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck
4 
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11 
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14 
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 THE SOFTWARE.
22 
23 */
24 
25 #ifndef CXXOPTS_HPP_INCLUDED
26 #define CXXOPTS_HPP_INCLUDED
27 
28 #include <cstring>
29 #include <cctype>
30 #include <exception>
31 #include <iostream>
32 #include <map>
33 #include <memory>
34 #include <regex>
35 #include <sstream>
36 #include <string>
37 #include <unordered_map>
38 #include <unordered_set>
39 #include <vector>
40 #include <limits>
41 
42 #ifdef __cpp_lib_optional
43 #include <optional>
44 #define CXXOPTS_HAS_OPTIONAL
45 #endif
46 
47 #define CXXOPTS__VERSION_MAJOR 2
48 #define CXXOPTS__VERSION_MINOR 2
49 #define CXXOPTS__VERSION_PATCH 0
50 
51 namespace cxxopts {
52  static constexpr struct {
53  uint8_t major, minor, patch;
55 } // namespace cxxopts
56 
57 //when we ask cxxopts to use Unicode, help strings are processed using ICU,
58 //which results in the correct lengths being computed for strings when they
59 //are formatted for the help output
60 //it is necessary to make sure that <unicode/unistr.h> can be found by the
61 //compiler, and that icu-uc is linked in to the binary.
62 
63 #ifdef CXXOPTS_USE_UNICODE
64 #include <unicode/unistr.h>
65 
66 namespace cxxopts {
67  typedef icu::UnicodeString String;
68 
69  inline String toLocalString(std::string s) { return icu::UnicodeString::fromUTF8(std::move(s)); }
70 
71  class UnicodeStringIterator : public std::iterator<std::forward_iterator_tag, int32_t> {
72  public:
73  UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos) : s(string), i(pos) {}
74 
75  value_type operator*() const { return s->char32At(i); }
76 
77  bool operator==(const UnicodeStringIterator& rhs) const { return s == rhs.s && i == rhs.i; }
78 
79  bool operator!=(const UnicodeStringIterator& rhs) const { return !(*this == rhs); }
80 
81  UnicodeStringIterator& operator++() {
82  ++i;
83  return *this;
84  }
85 
86  UnicodeStringIterator operator+(int32_t v) { return UnicodeStringIterator(s, i + v); }
87 
88  private:
89  const icu::UnicodeString* s;
90  int32_t i;
91  };
92 
93  inline String& stringAppend(String& s, String a) { return s.append(std::move(a)); }
94 
95  inline String& stringAppend(String& s, int n, UChar32 c) {
96  for (int i = 0; i != n; ++i) {
97  s.append(c);
98  }
99 
100  return s;
101  }
102 
103  template <typename Iterator>
104  String& stringAppend(String& s, Iterator begin, Iterator end) {
105  while (begin != end) {
106  s.append(*begin);
107  ++begin;
108  }
109 
110  return s;
111  }
112 
113  inline size_t stringLength(const String& s) { return s.length(); }
114 
115  inline std::string toUTF8String(const String& s) {
117  s.toUTF8String(result);
118 
119  return result;
120  }
121 
122  inline bool empty(const String& s) { return s.isEmpty(); }
123 } // namespace cxxopts
124 
125 namespace std {
126  inline cxxopts::UnicodeStringIterator begin(const icu::UnicodeString& s) {
127  return cxxopts::UnicodeStringIterator(&s, 0);
128  }
129 
130  inline cxxopts::UnicodeStringIterator end(const icu::UnicodeString& s) {
131  return cxxopts::UnicodeStringIterator(&s, s.length());
132  }
133 } // namespace std
134 
135 //ifdef CXXOPTS_USE_UNICODE
136 #else
137 
138 namespace cxxopts {
140 
141  template <typename T>
143  return std::forward<T>(t);
144  }
145 
146  inline size_t stringLength(const String& s) { return s.length(); }
147 
148  inline String& stringAppend(String& s, String a) { return s.append(std::move(a)); }
149 
150  inline String& stringAppend(String& s, size_t n, char c) { return s.append(n, c); }
151 
152  template <typename Iterator>
154  return s.append(begin, end);
155  }
156 
157  template <typename T>
159  return std::forward<T>(t);
160  }
161 
162  inline bool empty(const std::string& s) { return s.empty(); }
163 } // namespace cxxopts
164 
165 //ifdef CXXOPTS_USE_UNICODE
166 #endif
167 
168 namespace cxxopts {
169  namespace {
170 #ifdef _WIN32
171  const std::string LQUOTE("\'");
172  const std::string RQUOTE("\'");
173 #else
174  const std::string LQUOTE("‘");
175  const std::string RQUOTE("’");
176 #endif
177  } // namespace
178 
179  class Value : public std::enable_shared_from_this<Value> {
180  public:
181  virtual ~Value() = default;
182 
183  virtual std::shared_ptr<Value> clone() const = 0;
184 
185  virtual void parse(const std::string& text) const = 0;
186 
187  virtual void parse() const = 0;
188 
189  virtual bool has_default() const = 0;
190 
191  virtual bool is_container() const = 0;
192 
193  virtual bool has_implicit() const = 0;
194 
195  virtual std::string get_default_value() const = 0;
196 
197  virtual std::string get_implicit_value() const = 0;
198 
199  virtual std::shared_ptr<Value> default_value(const std::string& value) = 0;
200 
201  virtual std::shared_ptr<Value> implicit_value(const std::string& value) = 0;
202 
203  virtual bool is_boolean() const = 0;
204  };
205 
207  public:
208  OptionException(const std::string& message) : m_message(message) {}
209 
210  virtual const char* what() const noexcept { return m_message.c_str(); }
211 
212  private:
214  };
215 
217  public:
218  OptionSpecException(const std::string& message) : OptionException(message) {}
219  };
220 
222  public:
223  OptionParseException(const std::string& message) : OptionException(message) {}
224  };
225 
227  public:
229  : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists") {}
230  };
231 
233  public:
235  : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE) {}
236  };
237 
239  public:
241  : OptionParseException("Argument " + LQUOTE + text + RQUOTE + " starts with a - but has incorrect syntax") {}
242  };
243 
245  public:
247  : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist") {}
248  };
249 
251  public:
253  : OptionParseException("Option " + LQUOTE + option + RQUOTE + " is missing an argument") {}
254  };
255 
257  public:
259  : OptionParseException("Option " + LQUOTE + option + RQUOTE + " requires an argument") {}
260  };
261 
263  public:
265  : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not take an argument, but argument " +
266  LQUOTE + arg + RQUOTE + " given") {}
267  };
268 
270  public:
272  : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present") {}
273  };
274 
276  public:
278  : OptionParseException("Argument " + LQUOTE + arg + RQUOTE + " failed to parse") {}
279  };
280 
282  public:
284  : OptionParseException("Option " + LQUOTE + option + RQUOTE + " is required but not present") {}
285  };
286 
287  namespace values {
288  namespace {
289  std::basic_regex<char> integer_pattern("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
290  std::basic_regex<char> truthy_pattern("(t|T)(rue)?");
291  std::basic_regex<char> falsy_pattern("((f|F)(alse)?)?");
292  } // namespace
293 
294  namespace detail {
295  template <typename T, bool B>
296  struct SignedCheck;
297 
298  template <typename T>
299  struct SignedCheck<T, true> {
300  template <typename U>
301  void operator()(bool negative, U u, const std::string& text) {
302  if (negative) {
303  if (u > static_cast<U>(-(std::numeric_limits<T>::min)())) {
305  }
306  } else {
307  if (u > static_cast<U>((std::numeric_limits<T>::max)())) {
309  }
310  }
311  }
312  };
313 
314  template <typename T>
315  struct SignedCheck<T, false> {
316  template <typename U>
317  void operator()(bool, U, const std::string&) {}
318  };
319 
320  template <typename T, typename U>
321  void check_signed_range(bool negative, U value, const std::string& text) {
323  }
324  } // namespace detail
325 
326  template <typename R, typename T>
327  R checked_negate(T&& t, const std::string&, std::true_type) {
328  // if we got to here, then `t` is a positive number that fits into
329  // `R`. So to avoid MSVC C4146, we first cast it to `R`.
330  // See https://github.com/jarro2783/cxxopts/issues/62 for more details.
331  return -static_cast<R>(t);
332  }
333 
334  template <typename R, typename T>
335  T checked_negate(T&&, const std::string& text, std::false_type) {
337  }
338 
339  template <typename T>
341  std::smatch match;
342  std::regex_match(text, match, integer_pattern);
343 
344  if (match.length() == 0) {
346  }
347 
348  if (match.length(4) > 0) {
349  value = 0;
350  return;
351  }
352 
353  using US = typename std::make_unsigned<T>::type;
354 
355  constexpr auto umax = (std::numeric_limits<US>::max)();
356  constexpr bool is_signed = std::numeric_limits<T>::is_signed;
357  const bool negative = match.length(1) > 0;
358  const uint8_t base = match.length(2) > 0 ? 16 : 10;
359 
360  auto value_match = match[3];
361 
362  US result = 0;
363 
364  for (auto iter = value_match.first; iter != value_match.second; ++iter) {
365  US digit = 0;
366 
367  if (*iter >= '0' && *iter <= '9') {
368  digit = *iter - '0';
369  } else if (base == 16 && *iter >= 'a' && *iter <= 'f') {
370  digit = *iter - 'a' + 10;
371  } else if (base == 16 && *iter >= 'A' && *iter <= 'F') {
372  digit = *iter - 'A' + 10;
373  } else {
375  }
376 
377  if (umax - digit < result * base) {
379  }
380 
381  result = result * base + digit;
382  }
383 
384  detail::check_signed_range<T>(negative, result, text);
385 
386  if (negative) {
387  value = checked_negate<T>(result, text, std::integral_constant<bool, is_signed>());
388  } else {
389  value = result;
390  }
391  }
392 
393  template <typename T>
395  std::stringstream in(text);
396  in >> value;
397  if (!in) {
399  }
400  }
401 
402  inline void parse_value(const std::string& text, uint8_t& value) { integer_parser(text, value); }
403 
404  inline void parse_value(const std::string& text, int8_t& value) { integer_parser(text, value); }
405 
406  inline void parse_value(const std::string& text, uint16_t& value) { integer_parser(text, value); }
407 
408  inline void parse_value(const std::string& text, int16_t& value) { integer_parser(text, value); }
409 
410  inline void parse_value(const std::string& text, uint32_t& value) { integer_parser(text, value); }
411 
412  inline void parse_value(const std::string& text, int32_t& value) { integer_parser(text, value); }
413 
415 
416  inline void parse_value(const std::string& text, int64_t& value) { integer_parser(text, value); }
417 
418  inline void parse_value(const std::string& text, bool& value) {
419  std::smatch result;
420  std::regex_match(text, result, truthy_pattern);
421 
422  if (!result.empty()) {
423  value = true;
424  return;
425  }
426 
427  std::regex_match(text, result, falsy_pattern);
428  if (!result.empty()) {
429  value = false;
430  return;
431  }
432 
434  }
435 
436  inline void parse_value(const std::string& text, std::string& value) { value = text; }
437 
438  // The fallback parser. It uses the stringstream parser to parse all types
439  // that have not been overloaded explicitly. It has to be placed in the
440  // source code before all other more specialized templates.
441  template <typename T>
442  void parse_value(const std::string& text, T& value) {
444  }
445 
446  template <typename T>
447  void parse_value(const std::string& text, std::vector<T>& value) {
448  T v;
449  parse_value(text, v);
450  value.push_back(v);
451  }
452 
453 #ifdef CXXOPTS_HAS_OPTIONAL
454  template <typename T>
455  void parse_value(const std::string& text, std::optional<T>& value) {
456  T result;
459  }
460 #endif
461 
462  template <typename T>
464  static constexpr bool value = false;
465  };
466 
467  template <typename T>
469  static constexpr bool value = true;
470  };
471 
472  template <typename T>
473  class Abstract_value : public Value {
475 
476  public:
477  Abstract_value() : m_result(std::make_shared<T>()), m_store(m_result.get()) {}
478 
480 
481  virtual ~Abstract_value() = default;
482 
484  if (rhs.m_result) {
485  m_result = std::make_shared<T>();
486  m_store = m_result.get();
487  } else {
488  m_store = rhs.m_store;
489  }
490 
491  m_default = rhs.m_default;
492  m_implicit = rhs.m_implicit;
495  }
496 
497  void parse(const std::string& text) const { parse_value(text, *m_store); }
498 
499  bool is_container() const { return Type_is_container<T>::value; }
500 
502 
503  bool has_default() const { return m_default; }
504 
505  bool has_implicit() const { return m_implicit; }
506 
507  std::shared_ptr<Value> default_value(const std::string& value) {
508  m_default = true;
510  return shared_from_this();
511  }
512 
513  std::shared_ptr<Value> implicit_value(const std::string& value) {
514  m_implicit = true;
516  return shared_from_this();
517  }
518 
520 
522 
523  bool is_boolean() const { return std::is_same<T, bool>::value; }
524 
525  const T& get() const {
526  if (m_store == nullptr) {
527  return *m_result;
528  } else {
529  return *m_store;
530  }
531  }
532 
533  protected:
534  std::shared_ptr<T> m_result;
536 
537  bool m_default = false;
538  bool m_implicit = false;
539 
542  };
543 
544  template <typename T>
545  class Standard_value : public Abstract_value<T> {
546  public:
548 
549  std::shared_ptr<Value> clone() const { return std::make_shared<Standard_value<T>>(*this); }
550  };
551 
552  template <>
553  class Standard_value<bool> : public Abstract_value<bool> {
554  public:
555  ~Standard_value() = default;
556 
557  Standard_value() { set_default_and_implicit(); }
558 
559  Standard_value(bool* b) : Abstract_value(b) { set_default_and_implicit(); }
560 
561  std::shared_ptr<Value> clone() const { return std::make_shared<Standard_value<bool>>(*this); }
562 
563  private:
565  m_default = true;
566  m_default_value = "false";
567  m_implicit = true;
568  m_implicit_value = "true";
569  }
570  };
571  } // namespace values
572 
573  template <typename T>
574  std::shared_ptr<Value> value() {
575  return std::make_shared<values::Standard_value<T>>();
576  }
577 
578  template <typename T>
579  std::shared_ptr<Value> value(T& t) {
580  return std::make_shared<values::Standard_value<T>>(&t);
581  }
582 
583  class OptionAdder;
584 
586  public:
587  OptionDetails(const std::string& short_,
588  const std::string& long_,
589  const String& desc,
590  std::shared_ptr<const Value> val)
591  : m_short(short_), m_long(long_), m_desc(desc), m_value(val), m_count(0) {}
592 
594  m_value = rhs.m_value->clone();
595  }
596 
597  OptionDetails(OptionDetails&& rhs) = default;
598 
599  const String& description() const { return m_desc; }
600 
601  const Value& value() const { return *m_value; }
602 
603  std::shared_ptr<Value> make_storage() const { return m_value->clone(); }
604 
605  const std::string& short_name() const { return m_short; }
606 
607  const std::string& long_name() const { return m_long; }
608 
609  private:
613  std::shared_ptr<const Value> m_value;
614  int m_count;
615  };
616 
628  };
629 
633  std::vector<HelpOptionDetails> options;
634  };
635 
636  class OptionValue {
637  public:
638  void parse(std::shared_ptr<const OptionDetails> details, const std::string& text) {
640  ++m_count;
641  m_value->parse(text);
642  }
643 
644  void parse_default(std::shared_ptr<const OptionDetails> details) {
646  m_value->parse();
647  }
648 
649  size_t count() const { return m_count; }
650 
651  template <typename T>
652  const T& as() const {
653  if (m_value == nullptr) {
654  throw std::domain_error("No value");
655  }
656 
657 #ifdef CXXOPTS_NO_RTTI
658  return static_cast<const values::Standard_value<T>&>(*m_value).get();
659 #else
660  return dynamic_cast<const values::Standard_value<T>&>(*m_value).get();
661 #endif
662  }
663 
664  private:
665  void ensure_value(std::shared_ptr<const OptionDetails> details) {
666  if (m_value == nullptr) {
667  m_value = details->make_storage();
668  }
669  }
670 
671  std::shared_ptr<Value> m_value;
672  size_t m_count = 0;
673  };
674 
675  class KeyValue {
676  public:
677  KeyValue(std::string key_, std::string value_) : m_key(std::move(key_)), m_value(std::move(value_)) {}
678 
679  const std::string& key() const { return m_key; }
680 
681  const std::string& value() const { return m_value; }
682 
683  template <typename T>
684  T as() const {
685  T result;
687  return result;
688  }
689 
690  private:
693  };
694 
695  class ParseResult {
696  public:
697  ParseResult(const std::shared_ptr<std::unordered_map<std::string, std::shared_ptr<OptionDetails>>>,
698  std::vector<std::string>,
699  bool allow_unrecognised,
700  int&,
701  char**&);
702 
703  size_t count(const std::string& o) const {
704  auto iter = m_options->find(o);
705  if (iter == m_options->end()) {
706  return 0;
707  }
708 
709  auto riter = m_results.find(iter->second);
710 
711  return riter->second.count();
712  }
713 
714  const OptionValue& operator[](const std::string& option) const {
715  auto iter = m_options->find(option);
716 
717  if (iter == m_options->end()) {
719  }
720 
721  auto riter = m_results.find(iter->second);
722 
723  return riter->second;
724  }
725 
726  const std::vector<KeyValue>& arguments() const { return m_sequential; }
727 
728  private:
729  void parse(int& argc, char**& argv);
730 
731  void add_to_option(const std::string& option, const std::string& arg);
732 
734 
735  void parse_option(std::shared_ptr<OptionDetails> value, const std::string& name, const std::string& arg = "");
736 
737  void parse_default(std::shared_ptr<OptionDetails> details);
738 
739  void checked_parse_arg(
740  int argc, char* argv[], int& current, std::shared_ptr<OptionDetails> value, const std::string& name);
741 
742  const std::shared_ptr<std::unordered_map<std::string, std::shared_ptr<OptionDetails>>> m_options;
743  std::vector<std::string> m_positional;
744  std::vector<std::string>::iterator m_next_positional;
745  std::unordered_set<std::string> m_positional_set;
746  std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results;
747 
749 
750  std::vector<KeyValue> m_sequential;
751  };
752 
753  class Options {
754  typedef std::unordered_map<std::string, std::shared_ptr<OptionDetails>> OptionMap;
755 
756  public:
757  Options(std::string program, std::string help_string = "")
758  : m_program(std::move(program)),
759  m_help_string(toLocalString(std::move(help_string))),
760  m_custom_help("[OPTION...]"),
761  m_positional_help("positional parameters"),
764  m_options(std::make_shared<OptionMap>()),
766 
768  m_positional_help = std::move(help_text);
769  return *this;
770  }
771 
773  m_custom_help = std::move(help_text);
774  return *this;
775  }
776 
778  m_show_positional = true;
779  return *this;
780  }
781 
783  m_allow_unrecognised = true;
784  return *this;
785  }
786 
787  ParseResult parse(int& argc, char**& argv);
788 
790 
791  void add_option(const std::string& group,
792  const std::string& s,
793  const std::string& l,
795  std::shared_ptr<const Value> value,
796  std::string arg_help);
797 
798  //parse positional arguments into the given option
800 
801  void parse_positional(std::vector<std::string> options);
802 
803  void parse_positional(std::initializer_list<std::string> options);
804 
805  template <typename Iterator>
806  void parse_positional(Iterator begin, Iterator end) {
807  parse_positional(std::vector<std::string>{begin, end});
808  }
809 
810  std::string help(const std::vector<std::string>& groups = {}) const;
811 
812  const std::vector<std::string> groups() const;
813 
814  const HelpGroupDetails& group_help(const std::string& group) const;
815 
816  private:
817  void add_one_option(const std::string& option, std::shared_ptr<OptionDetails> details);
818 
819  String help_one_group(const std::string& group) const;
820 
821  void generate_group_help(String& result, const std::vector<std::string>& groups) const;
822 
824 
831 
832  std::shared_ptr<OptionMap> m_options;
833  std::vector<std::string> m_positional;
834  std::vector<std::string>::iterator m_next_positional;
835  std::unordered_set<std::string> m_positional_set;
836 
837  //mapping from groups to help options
838  std::map<std::string, HelpGroupDetails> m_help;
839  };
840 
841  class OptionAdder {
842  public:
844 
846  const std::string& desc,
847  std::shared_ptr<const Value> value = ::cxxopts::value<bool>(),
848  std::string arg_help = "");
849 
850  private:
853  };
854 
855  namespace {
856  constexpr int OPTION_LONGEST = 30;
857  constexpr int OPTION_DESC_GAP = 2;
858 
859  std::basic_regex<char> option_matcher("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
860 
861  std::basic_regex<char> option_specifier("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
862 
863  String format_option(const HelpOptionDetails& o) {
864  auto& s = o.s;
865  auto& l = o.l;
866 
867  String result = " ";
868 
869  if (s.size() > 0) {
870  result += "-" + toLocalString(s) + ",";
871  } else {
872  result += " ";
873  }
874 
875  if (l.size() > 0) {
876  result += " --" + toLocalString(l);
877  }
878 
879  auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg";
880 
881  if (!o.is_boolean) {
882  if (o.has_implicit) {
883  result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
884  } else {
885  result += " " + arg;
886  }
887  }
888 
889  return result;
890  }
891 
892  String format_description(const HelpOptionDetails& o, size_t start, size_t width) {
893  auto desc = o.desc;
894 
895  if (o.has_default && (!o.is_boolean || o.default_value != "false")) {
896  desc += toLocalString(" (default: " + o.default_value + ")");
897  }
898 
899  String result;
900 
901  auto current = std::begin(desc);
902  auto startLine = current;
903  auto lastSpace = current;
904 
905  auto size = size_t{};
906 
907  while (current != std::end(desc)) {
908  if (*current == ' ') {
909  lastSpace = current;
910  }
911 
912  if (*current == '\n') {
913  startLine = current + 1;
914  lastSpace = startLine;
915  } else if (size > width) {
916  if (lastSpace == startLine) {
917  stringAppend(result, startLine, current + 1);
918  stringAppend(result, "\n");
919  stringAppend(result, start, ' ');
920  startLine = current + 1;
921  lastSpace = startLine;
922  } else {
923  stringAppend(result, startLine, lastSpace);
924  stringAppend(result, "\n");
925  stringAppend(result, start, ' ');
926  startLine = lastSpace + 1;
927  }
928  size = 0;
929  } else {
930  ++size;
931  }
932 
933  ++current;
934  }
935 
936  //append whatever is left
937  stringAppend(result, startLine, current);
938 
939  return result;
940  }
941  } // namespace
942 
944  const std::shared_ptr<std::unordered_map<std::string, std::shared_ptr<OptionDetails>>> options,
945  std::vector<std::string> positional,
946  bool allow_unrecognised,
947  int& argc,
948  char**& argv)
949  : m_options(options),
950  m_positional(std::move(positional)),
951  m_next_positional(m_positional.begin()),
952  m_allow_unrecognised(allow_unrecognised) {
953  parse(argc, argv);
954  }
955 
957 
959  const std::string& desc,
960  std::shared_ptr<const Value> value,
961  std::string arg_help) {
962  std::match_results<const char*> result;
963  std::regex_match(opts.c_str(), result, option_specifier);
964 
965  if (result.empty()) {
967  }
968 
969  const auto& short_match = result[2];
970  const auto& long_match = result[3];
971 
972  if (!short_match.length() && !long_match.length()) {
974  } else if (long_match.length() == 1 && short_match.length()) {
976  }
977 
978  auto option_names = [](const std::sub_match<const char*>& short_, const std::sub_match<const char*>& long_) {
979  if (long_.length() == 1) {
980  return std::make_tuple(long_.str(), short_.str());
981  } else {
982  return std::make_tuple(short_.str(), long_.str());
983  }
984  }(short_match, long_match);
985 
987  m_group, std::get<0>(option_names), std::get<1>(option_names), desc, value, std::move(arg_help));
988 
989  return *this;
990  }
991 
992  inline void ParseResult::parse_default(std::shared_ptr<OptionDetails> details) {
993  m_results[details].parse_default(details);
994  }
995 
996  inline void ParseResult::parse_option(std::shared_ptr<OptionDetails> value,
997  const std::string& /*name*/,
998  const std::string& arg) {
999  auto& result = m_results[value];
1000  result.parse(value, arg);
1001 
1002  m_sequential.emplace_back(value->long_name(), arg);
1003  }
1004 
1006  int argc, char* argv[], int& current, std::shared_ptr<OptionDetails> value, const std::string& name) {
1007  if (current + 1 >= argc) {
1008  if (value->value().has_implicit()) {
1009  parse_option(value, name, value->value().get_implicit_value());
1010  } else {
1012  }
1013  } else {
1014  if (value->value().has_implicit()) {
1015  parse_option(value, name, value->value().get_implicit_value());
1016  } else {
1017  parse_option(value, name, argv[current + 1]);
1018  ++current;
1019  }
1020  }
1021  }
1022 
1024  auto iter = m_options->find(option);
1025 
1026  if (iter == m_options->end()) {
1028  }
1029 
1030  parse_option(iter->second, option, arg);
1031  }
1032 
1034  while (m_next_positional != m_positional.end()) {
1035  auto iter = m_options->find(*m_next_positional);
1036  if (iter != m_options->end()) {
1037  auto& result = m_results[iter->second];
1038  if (!iter->second->value().is_container()) {
1039  if (result.count() == 0) {
1042  return true;
1043  } else {
1045  continue;
1046  }
1047  } else {
1049  return true;
1050  }
1051  }
1053  }
1054 
1055  return false;
1056  }
1057 
1059  parse_positional(std::vector<std::string>{std::move(option)});
1060  }
1061 
1062  inline void Options::parse_positional(std::vector<std::string> options) {
1064  m_next_positional = m_positional.begin();
1065 
1066  m_positional_set.insert(m_positional.begin(), m_positional.end());
1067  }
1068 
1069  inline void Options::parse_positional(std::initializer_list<std::string> options) {
1070  parse_positional(std::vector<std::string>(std::move(options)));
1071  }
1072 
1073  inline ParseResult Options::parse(int& argc, char**& argv) {
1075  return result;
1076  }
1077 
1078  inline void ParseResult::parse(int& argc, char**& argv) {
1079  int current = 1;
1080 
1081  int nextKeep = 1;
1082 
1083  bool consume_remaining = false;
1084 
1085  while (current != argc) {
1086  if (strcmp(argv[current], "--") == 0) {
1087  consume_remaining = true;
1088  ++current;
1089  break;
1090  }
1091 
1092  std::match_results<const char*> result;
1093  std::regex_match(argv[current], result, option_matcher);
1094 
1095  if (result.empty()) {
1096  //not a flag
1097 
1098  // but if it starts with a `-`, then it's an error
1099  if (argv[current][0] == '-' && argv[current][1] != '\0') {
1100  throw Option_syntax_exception(argv[current]);
1101  }
1102 
1103  //if true is returned here then it was consumed, otherwise it is
1104  //ignored
1105  if (consume_positional(argv[current])) {
1106  } else {
1107  argv[nextKeep] = argv[current];
1108  ++nextKeep;
1109  }
1110  //if we return from here then it was parsed successfully, so continue
1111  } else {
1112  //short or long option?
1113  if (result[4].length() != 0) {
1114  const std::string& s = result[4];
1115 
1116  for (std::size_t i = 0; i != s.size(); ++i) {
1117  std::string name(1, s[i]);
1118  auto iter = m_options->find(name);
1119 
1120  if (iter == m_options->end()) {
1121  if (m_allow_unrecognised) {
1122  continue;
1123  } else {
1124  //error
1126  }
1127  }
1128 
1129  auto value = iter->second;
1130 
1131  if (i + 1 == s.size()) {
1132  //it must be the last argument
1133  checked_parse_arg(argc, argv, current, value, name);
1134  } else if (value->value().has_implicit()) {
1135  parse_option(value, name, value->value().get_implicit_value());
1136  } else {
1137  //error
1139  }
1140  }
1141  } else if (result[1].length() != 0) {
1142  const std::string& name = result[1];
1143 
1144  auto iter = m_options->find(name);
1145 
1146  if (iter == m_options->end()) {
1147  if (m_allow_unrecognised) {
1148  // keep unrecognised options in argument list, skip to next argument
1149  argv[nextKeep] = argv[current];
1150  ++nextKeep;
1151  ++current;
1152  continue;
1153  } else {
1154  //error
1156  }
1157  }
1158 
1159  auto opt = iter->second;
1160 
1161  //equals provided for long option?
1162  if (result[2].length() != 0) {
1163  //parse the option given
1164 
1165  parse_option(opt, name, result[3]);
1166  } else {
1167  //parse the next argument
1168  checked_parse_arg(argc, argv, current, opt, name);
1169  }
1170  }
1171  }
1172 
1173  ++current;
1174  }
1175 
1176  for (auto& opt : *m_options) {
1177  auto& detail = opt.second;
1178  auto& value = detail->value();
1179 
1180  auto& store = m_results[detail];
1181 
1182  if (!store.count() && value.has_default()) {
1184  }
1185  }
1186 
1187  if (consume_remaining) {
1188  while (current < argc) {
1189  if (!consume_positional(argv[current])) {
1190  break;
1191  }
1192  ++current;
1193  }
1194 
1195  //adjust argv for any that couldn't be swallowed
1196  while (current != argc) {
1197  argv[nextKeep] = argv[current];
1198  ++nextKeep;
1199  ++current;
1200  }
1201  }
1202 
1203  argc = nextKeep;
1204  }
1205 
1207  const std::string& s,
1208  const std::string& l,
1209  std::string desc,
1210  std::shared_ptr<const Value> value,
1211  std::string arg_help) {
1212  auto stringDesc = toLocalString(std::move(desc));
1213  auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);
1214 
1215  if (s.size() > 0) {
1217  }
1218 
1219  if (l.size() > 0) {
1221  }
1222 
1223  //add the help details
1224  auto& options = m_help[group];
1225 
1226  options.options.emplace_back(HelpOptionDetails{s,
1227  l,
1228  stringDesc,
1229  value->has_default(),
1230  value->get_default_value(),
1231  value->has_implicit(),
1232  value->get_implicit_value(),
1233  std::move(arg_help),
1234  value->is_container(),
1235  value->is_boolean()});
1236  }
1237 
1238  inline void Options::add_one_option(const std::string& option, std::shared_ptr<OptionDetails> details) {
1239  auto in = m_options->emplace(option, details);
1240 
1241  if (!in.second) {
1242  throw Option_exists_error(option);
1243  }
1244  }
1245 
1247  typedef std::vector<std::pair<String, String>> OptionHelp;
1248 
1249  auto group = m_help.find(g);
1250  if (group == m_help.end()) {
1251  return "";
1252  }
1253 
1254  OptionHelp format;
1255 
1256  size_t longest = 0;
1257 
1258  String result;
1259 
1260  if (!g.empty()) {
1261  result += toLocalString(" " + g + " options:\n");
1262  }
1263 
1264  for (const auto& o : group->second.options) {
1265  if (o.is_container && m_positional_set.find(o.l) != m_positional_set.end() && !m_show_positional) {
1266  continue;
1267  }
1268 
1269  auto s = format_option(o);
1270  longest = (std::max)(longest, stringLength(s));
1271  format.push_back(std::make_pair(s, String()));
1272  }
1273 
1274  longest = (std::min)(longest, static_cast<size_t>(OPTION_LONGEST));
1275 
1276  //widest allowed description
1277  auto allowed = size_t{76} - longest - OPTION_DESC_GAP;
1278 
1279  auto fiter = format.begin();
1280  for (const auto& o : group->second.options) {
1281  if (o.is_container && m_positional_set.find(o.l) != m_positional_set.end() && !m_show_positional) {
1282  continue;
1283  }
1284 
1285  auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
1286 
1287  result += fiter->first;
1288  if (stringLength(fiter->first) > longest) {
1289  result += '\n';
1290  result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
1291  } else {
1292  result += toLocalString(std::string(longest + OPTION_DESC_GAP - stringLength(fiter->first), ' '));
1293  }
1294  result += d;
1295  result += '\n';
1296 
1297  ++fiter;
1298  }
1299 
1300  return result;
1301  }
1302 
1303  inline void Options::generate_group_help(String& result, const std::vector<std::string>& print_groups) const {
1304  for (size_t i = 0; i != print_groups.size(); ++i) {
1305  const String& group_help_text = help_one_group(print_groups[i]);
1306  if (empty(group_help_text)) {
1307  continue;
1308  }
1309  result += group_help_text;
1310  if (i < print_groups.size() - 1) {
1311  result += '\n';
1312  }
1313  }
1314  }
1315 
1317  std::vector<std::string> all_groups;
1318  all_groups.reserve(m_help.size());
1319 
1320  for (auto& group : m_help) {
1321  all_groups.push_back(group.first);
1322  }
1323 
1324  generate_group_help(result, all_groups);
1325  }
1326 
1327  inline std::string Options::help(const std::vector<std::string>& help_groups) const {
1329 
1330  if (m_positional.size() > 0 && m_positional_help.size() > 0) {
1332  }
1333 
1334  result += "\n\n";
1335 
1336  if (help_groups.size() == 0) {
1338  } else {
1339  generate_group_help(result, help_groups);
1340  }
1341 
1342  return toUTF8String(result);
1343  }
1344 
1345  inline const std::vector<std::string> Options::groups() const {
1346  std::vector<std::string> g;
1347 
1348  std::transform(m_help.begin(),
1349  m_help.end(),
1350  std::back_inserter(g),
1351  [](const std::map<std::string, HelpGroupDetails>::value_type& pair) { return pair.first; });
1352 
1353  return g;
1354  }
1355 
1356  inline const HelpGroupDetails& Options::group_help(const std::string& group) const { return m_help.at(group); }
1357 
1358 } // namespace cxxopts
1359 
1360 #endif //CXXOPTS_HPP_INCLUDED
size
Write out results.
void checked_parse_arg(int argc, char *argv[], int &current, std::shared_ptr< OptionDetails > value, const std::string &name)
Definition: cxxopts.h:1005
Definition: start.py:1
static constexpr struct cxxopts::@964 version
std::string description
Definition: cxxopts.h:632
std::string implicit_value
Definition: cxxopts.h:624
std::string m_long
Definition: cxxopts.h:611
bool consume_positional(std::string a)
Definition: cxxopts.h:1033
std::vector< std::string >::iterator m_next_positional
Definition: cxxopts.h:744
std::vector< std::string > m_positional
Definition: cxxopts.h:833
void parse_default(std::shared_ptr< const OptionDetails > details)
Definition: cxxopts.h:644
OptionParseException(const std::string &message)
Definition: cxxopts.h:223
KeyValue(std::string key_, std::string value_)
Definition: cxxopts.h:677
std::string m_message
Definition: cxxopts.h:213
void operator()(bool negative, U u, const std::string &text)
Definition: cxxopts.h:301
virtual bool has_implicit() const =0
Option_not_exists_exception(const std::string &option)
Definition: cxxopts.h:246
#define CXXOPTS__VERSION_MAJOR
Definition: cxxopts.h:47
void stringstream_parser(const std::string &text, T &value)
Definition: cxxopts.h:394
Option_required_exception(const std::string &option)
Definition: cxxopts.h:283
OptionAdder add_options(std::string group="")
Definition: cxxopts.h:956
uint8_t minor
Definition: cxxopts.h:53
std::string m_custom_help
Definition: cxxopts.h:827
virtual bool is_container() const =0
std::shared_ptr< Value > default_value(const std::string &value)
Definition: cxxopts.h:507
MatrixMeschach operator+(const MatrixMeschach &mat1, const MatrixMeschach &mat2)
std::shared_ptr< T > m_result
Definition: cxxopts.h:534
Options & show_positional_help()
Definition: cxxopts.h:777
std::string m_group
Definition: cxxopts.h:852
std::string help(const std::vector< std::string > &groups={}) const
Definition: cxxopts.h:1327
void parse(int &argc, char **&argv)
Definition: cxxopts.h:1078
const std::string & key() const
Definition: cxxopts.h:679
uint8_t patch
Definition: cxxopts.h:53
std::map< std::string, HelpGroupDetails > m_help
Definition: cxxopts.h:838
constexpr Process operator++(Process p)
Definition: DataFormats.h:68
std::shared_ptr< Value > make_storage() const
Definition: cxxopts.h:603
Missing_argument_exception(const std::string &option)
Definition: cxxopts.h:252
void add_to_option(const std::string &option, const std::string &arg)
Definition: cxxopts.h:1023
void integer_parser(const std::string &text, T &value)
Definition: cxxopts.h:340
#define CXXOPTS__VERSION_MINOR
Definition: cxxopts.h:48
Options & allow_unrecognised_options()
Definition: cxxopts.h:782
void parse_default(std::shared_ptr< OptionDetails > details)
Definition: cxxopts.h:992
std::shared_ptr< const Value > m_value
Definition: cxxopts.h:613
std::shared_ptr< Value > implicit_value(const std::string &value)
Definition: cxxopts.h:513
Options & positional_help(std::string help_text)
Definition: cxxopts.h:767
std::shared_ptr< Value > clone() const
Definition: cxxopts.h:549
std::unordered_map< std::shared_ptr< OptionDetails >, OptionValue > m_results
Definition: cxxopts.h:746
virtual std::shared_ptr< Value > default_value(const std::string &value)=0
String help_one_group(const std::string &group) const
Definition: cxxopts.h:1246
A arg
Definition: Factorize.h:31
T toLocalString(T &&t)
Definition: cxxopts.h:142
bool m_allow_unrecognised
Definition: cxxopts.h:748
size_t count() const
Definition: cxxopts.h:649
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e g
Definition: Activities.doc:4
const Value & value() const
Definition: cxxopts.h:601
void operator()(bool, U, const std::string &)
Definition: cxxopts.h:317
void parse_value(const std::string &text, uint8_t &value)
Definition: cxxopts.h:402
OptionException(const std::string &message)
Definition: cxxopts.h:208
OptionDetails(const OptionDetails &rhs)
Definition: cxxopts.h:593
void add_option(const std::string &group, const std::string &s, const std::string &l, std::string desc, std::shared_ptr< const Value > value, std::string arg_help)
Definition: cxxopts.h:1206
std::vector< KeyValue > m_sequential
Definition: cxxopts.h:750
const std::vector< std::string > groups() const
Definition: cxxopts.h:1345
Options & m_options
Definition: cxxopts.h:851
std::string get_default_value() const
Definition: cxxopts.h:519
bool m_allow_unrecognised
Definition: cxxopts.h:830
virtual std::string get_default_value() const =0
bool empty(const std::string &s)
Definition: cxxopts.h:162
void generate_all_groups_help(String &result) const
Definition: cxxopts.h:1316
virtual const char * what() const noexcept
Definition: cxxopts.h:210
std::string m_key
Definition: cxxopts.h:691
ParseResult(const std::shared_ptr< std::unordered_map< std::string, std::shared_ptr< OptionDetails >>>, std::vector< std::string >, bool allow_unrecognised, int &, char **&)
Definition: cxxopts.h:943
ParseResult parse(int &argc, char **&argv)
Definition: cxxopts.h:1073
Invalid_option_format_error(const std::string &format)
Definition: cxxopts.h:234
Definition: helper.h:56
bool operator==(const QGLikelihoodParameters &lhs, const QGLikelihoodCategory &rhs)
Test if parameters are compatible with category.
std::shared_ptr< Value > value()
Definition: cxxopts.h:574
const String & description() const
Definition: cxxopts.h:599
Definition: value.py:1
void check_signed_range(bool negative, U value, const std::string &text)
Definition: cxxopts.h:321
std::vector< std::string >::iterator m_next_positional
Definition: cxxopts.h:834
std::string m_short
Definition: cxxopts.h:610
std::shared_ptr< Value > clone() const
Definition: cxxopts.h:561
T as() const
Definition: cxxopts.h:684
const std::vector< KeyValue > & arguments() const
Definition: cxxopts.h:726
std::string default_value
Definition: cxxopts.h:622
virtual bool has_default() const =0
void parse_positional(Iterator begin, Iterator end)
Definition: cxxopts.h:806
uint8_t major
Definition: cxxopts.h:53
d
Definition: ztail.py:151
Option_requires_argument_exception(const std::string &option)
Definition: cxxopts.h:258
std::string m_value
Definition: cxxopts.h:692
void add_one_option(const std::string &option, std::shared_ptr< OptionDetails > details)
Definition: cxxopts.h:1238
virtual std::shared_ptr< Value > clone() const =0
bool operator!=(DTCELinkId const &lhs, DTCELinkId const &rhs)
Definition: DTCELinkId.h:81
const std::shared_ptr< std::unordered_map< std::string, std::shared_ptr< OptionDetails > > > m_options
Definition: cxxopts.h:742
bool m_show_positional
Definition: cxxopts.h:829
Option_not_present_exception(const std::string &option)
Definition: cxxopts.h:271
unsigned long long uint64_t
Definition: Time.h:13
std::unordered_set< std::string > m_positional_set
Definition: cxxopts.h:745
virtual std::shared_ptr< Value > implicit_value(const std::string &value)=0
std::string String
Definition: cxxopts.h:139
std::unordered_set< std::string > m_positional_set
Definition: cxxopts.h:835
void parse_option(std::shared_ptr< OptionDetails > value, const std::string &name, const std::string &arg="")
Definition: cxxopts.h:996
std::vector< HelpOptionDetails > options
Definition: cxxopts.h:633
size_t stringLength(const String &s)
Definition: cxxopts.h:146
double b
Definition: hdecay.h:120
#define CXXOPTS__VERSION_PATCH
Definition: cxxopts.h:49
std::unordered_map< std::string, std::shared_ptr< OptionDetails > > OptionMap
Definition: cxxopts.h:754
std::shared_ptr< Value > value(T &t)
Definition: cxxopts.h:579
void generate_group_help(String &result, const std::vector< std::string > &groups) const
Definition: cxxopts.h:1303
String & stringAppend(String &s, String a)
Definition: cxxopts.h:148
std::string get_implicit_value() const
Definition: cxxopts.h:521
std::string m_positional_help
Definition: cxxopts.h:828
OptionAdder(Options &options, std::string group)
Definition: cxxopts.h:843
const std::string & short_name() const
Definition: cxxopts.h:605
const std::string & value() const
Definition: cxxopts.h:681
Options & custom_help(std::string help_text)
Definition: cxxopts.h:772
std::string toUTF8String(T &&t)
Definition: cxxopts.h:158
size_t count(const std::string &o) const
Definition: cxxopts.h:703
double a
Definition: hdecay.h:121
OptionSpecException(const std::string &message)
Definition: cxxopts.h:218
Options(std::string program, std::string help_string="")
Definition: cxxopts.h:757
OptionDetails(const std::string &short_, const std::string &long_, const String &desc, std::shared_ptr< const Value > val)
Definition: cxxopts.h:587
const T & as() const
Definition: cxxopts.h:652
void parse_positional(std::string option)
Definition: cxxopts.h:1058
String m_help_string
Definition: cxxopts.h:826
Argument_incorrect_type(const std::string &arg)
Definition: cxxopts.h:277
Option_exists_error(const std::string &option)
Definition: cxxopts.h:228
MatrixMeschach operator*(const MatrixMeschach &mat1, const MatrixMeschach &mat2)
void parse(const std::string &text) const
Definition: cxxopts.h:497
void parse(std::shared_ptr< const OptionDetails > details, const std::string &text)
Definition: cxxopts.h:638
Option_not_has_argument_exception(const std::string &option, const std::string &arg)
Definition: cxxopts.h:264
const OptionValue & operator[](const std::string &option) const
Definition: cxxopts.h:714
long double T
const HelpGroupDetails & group_help(const std::string &group) const
Definition: cxxopts.h:1356
virtual std::string get_implicit_value() const =0
void ensure_value(std::shared_ptr< const OptionDetails > details)
Definition: cxxopts.h:665
std::shared_ptr< OptionMap > m_options
Definition: cxxopts.h:832
virtual ~Abstract_value()=default
Abstract_value(const Abstract_value &rhs)
Definition: cxxopts.h:483
OptionAdder & operator()(const std::string &opts, const std::string &desc, std::shared_ptr< const Value > value=::cxxopts::value< bool >(), std::string arg_help="")
Definition: cxxopts.h:958
def move(src, dest)
Definition: eostools.py:511
std::string m_program
Definition: cxxopts.h:825
std::shared_ptr< Value > m_value
Definition: cxxopts.h:671
Option_syntax_exception(const std::string &text)
Definition: cxxopts.h:240
virtual bool is_boolean() const =0
R checked_negate(T &&t, const std::string &, std::true_type)
Definition: cxxopts.h:327
virtual ~Value()=default
virtual void parse() const =0
const std::string & long_name() const
Definition: cxxopts.h:607
std::vector< std::string > m_positional
Definition: cxxopts.h:743
const T & get() const
Definition: cxxopts.h:525
unsigned transform(const HcalDetId &id, unsigned transformCode)