4#pragma GCC system_header
8#pragma GCC diagnostic push
9#if defined __SANITIZE_ADDRESS__ && defined __OPTIMIZE__
10#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
43#ifndef CXXOPTS_HPP_INCLUDED
44#define CXXOPTS_HPP_INCLUDED
49#include <initializer_list>
56#include <unordered_map>
57#include <unordered_set>
61#ifdef CXXOPTS_NO_EXCEPTIONS
65#if defined(__GNUC__) && !defined(__clang__)
66#if (__GNUC__ * 10 + __GNUC_MINOR__) < 49
67#define CXXOPTS_NO_REGEX true
70#if defined(_MSC_VER) && !defined(__clang__)
71#define CXXOPTS_LINKONCE_CONST __declspec(selectany) extern
72#define CXXOPTS_LINKONCE __declspec(selectany) extern
74#define CXXOPTS_LINKONCE_CONST
75#define CXXOPTS_LINKONCE
78#ifndef CXXOPTS_NO_REGEX
84#if __has_include(<optional>)
86#ifdef __cpp_lib_optional
87#define CXXOPTS_HAS_OPTIONAL
92#if __cplusplus >= 201603L
93#define CXXOPTS_NODISCARD [[nodiscard]]
95#define CXXOPTS_NODISCARD
98#ifndef CXXOPTS_VECTOR_DELIMITER
99#define CXXOPTS_VECTOR_DELIMITER ','
102#define CXXOPTS__VERSION_MAJOR 3
103#define CXXOPTS__VERSION_MINOR 1
104#define CXXOPTS__VERSION_PATCH 1
106#if (__GNUC__ < 10 || (__GNUC__ == 10 && __GNUC_MINOR__ < 1)) && __GNUC__ >= 6
107#define CXXOPTS_NULL_DEREF_IGNORE
111#define DO_PRAGMA(x) _Pragma(#x)
112#define CXXOPTS_DIAGNOSTIC_PUSH DO_PRAGMA(GCC diagnostic push)
113#define CXXOPTS_DIAGNOSTIC_POP DO_PRAGMA(GCC diagnostic pop)
114#define CXXOPTS_IGNORE_WARNING(x) DO_PRAGMA(GCC diagnostic ignored x)
117#define CXXOPTS_DIAGNOSTIC_PUSH
118#define CXXOPTS_DIAGNOSTIC_POP
119#define CXXOPTS_IGNORE_WARNING(x)
122#ifdef CXXOPTS_NO_RTTI
123#define CXXOPTS_RTTI_CAST static_cast
125#define CXXOPTS_RTTI_CAST dynamic_cast
129 static constexpr struct {
130 uint8_t major, minor, patch;
131 } version = {CXXOPTS__VERSION_MAJOR, CXXOPTS__VERSION_MINOR, CXXOPTS__VERSION_PATCH};
140#ifdef CXXOPTS_USE_UNICODE
141#include <unicode/unistr.h>
145 using String = icu::UnicodeString;
147 inline String toLocalString(std::string s) {
148 return icu::UnicodeString::fromUTF8(std::move(s));
153 CXXOPTS_DIAGNOSTIC_PUSH
154 CXXOPTS_IGNORE_WARNING(
"-Wnon-virtual-dtor")
157 class UnicodeStringIterator {
159 using iterator_category = std::forward_iterator_tag;
160 using value_type = int32_t;
161 using difference_type = std::ptrdiff_t;
162 using pointer = value_type*;
163 using reference = value_type&;
165 UnicodeStringIterator(
const icu::UnicodeString*
string, int32_t pos) : s(string), i(pos) {}
167 value_type operator*()
const {
168 return s->char32At(i);
171 bool operator==(
const UnicodeStringIterator& rhs)
const {
172 return s == rhs.s && i == rhs.i;
175 bool operator!=(
const UnicodeStringIterator& rhs)
const {
176 return !(*
this == rhs);
179 UnicodeStringIterator& operator++() {
184 UnicodeStringIterator operator+(int32_t v) {
185 return UnicodeStringIterator(s, i + v);
189 const icu::UnicodeString* s;
193 CXXOPTS_DIAGNOSTIC_POP
195 inline String& stringAppend(String& s, String a) {
196 return s.append(std::move(a));
199 inline String& stringAppend(String& s, std::size_t n, UChar32 c) {
200 for (std::size_t i = 0; i != n; ++i) {
207 template <
typename Iterator>
208 String& stringAppend(String& s, Iterator begin, Iterator end) {
209 while (begin != end) {
217 inline std::size_t stringLength(
const String& s) {
221 inline std::string toUTF8String(
const String& s) {
223 s.toUTF8String(result);
228 inline bool empty(
const String& s) {
236 inline cxxopts::UnicodeStringIterator begin(
const icu::UnicodeString& s) {
237 return cxxopts::UnicodeStringIterator(&s, 0);
240 inline cxxopts::UnicodeStringIterator end(
const icu::UnicodeString& s) {
241 return cxxopts::UnicodeStringIterator(&s, s.length());
251 using String = std::string;
253 template <
typename T>
254 T toLocalString(T&& t) {
255 return std::forward<T>(t);
258 inline std::size_t stringLength(
const String& s) {
262 inline String& stringAppend(String& s,
const String& a) {
266 inline String& stringAppend(String& s, std::size_t n,
char c) {
267 return s.append(n, c);
270 template <
typename Iterator>
271 String& stringAppend(String& s, Iterator begin, Iterator end) {
272 return s.append(begin, end);
275 template <
typename T>
276 std::string toUTF8String(T&& t) {
277 return std::forward<T>(t);
280 inline bool empty(
const std::string& s) {
293 CXXOPTS_LINKONCE_CONST std::string LQUOTE(
"\'");
294 CXXOPTS_LINKONCE_CONST std::string RQUOTE(
"\'");
296 CXXOPTS_LINKONCE_CONST std::string LQUOTE(
"‘");
297 CXXOPTS_LINKONCE_CONST std::string RQUOTE(
"’");
305 CXXOPTS_DIAGNOSTIC_PUSH
306 CXXOPTS_IGNORE_WARNING(
"-Wnon-virtual-dtor")
309 CXXOPTS_IGNORE_WARNING("-Weffc++")
313 virtual ~Value() =
default;
315 virtual std::shared_ptr<Value> clone()
const = 0;
317 virtual void parse(
const std::string& text)
const = 0;
319 virtual void parse()
const = 0;
321 virtual bool has_default()
const = 0;
323 virtual bool is_container()
const = 0;
325 virtual bool has_implicit()
const = 0;
327 virtual std::string get_default_value()
const = 0;
329 virtual std::string get_implicit_value()
const = 0;
331 virtual std::shared_ptr<Value> default_value(
const std::string& value) = 0;
333 virtual std::shared_ptr<Value> implicit_value(
const std::string& value) = 0;
335 virtual std::shared_ptr<Value> no_implicit_value() = 0;
337 virtual bool is_boolean()
const = 0;
340 CXXOPTS_DIAGNOSTIC_POP
342 namespace exceptions {
346 explicit exception(std::string message) : m_message(std::move(message)) {}
349 const char* what()
const noexcept override {
350 return m_message.c_str();
354 std::string m_message;
370 :
specification(
"Option " + LQUOTE + option + RQUOTE +
" already exists") {}
376 :
specification(
"Invalid option format " + LQUOTE + format + RQUOTE) {}
383 "Argument " + LQUOTE + text + RQUOTE +
384 " starts with a - but has incorrect syntax"
391 :
parsing(
"Option " + LQUOTE + option + RQUOTE +
" does not exist") {}
397 :
parsing(
"Option " + LQUOTE + option + RQUOTE +
" is missing an argument") {}
403 :
parsing(
"Option " + LQUOTE + option + RQUOTE +
" requires an argument") {}
410 "Option " + LQUOTE + option + RQUOTE +
411 " does not take an argument, but argument " + LQUOTE + arg + RQUOTE +
" given"
418 :
parsing(
"Option " + LQUOTE + option + RQUOTE +
" not present") {}
425 !option.empty() ? (
"Option " + LQUOTE + option + RQUOTE +
" has no value")
426 :
"Option has no value"
433 :
parsing(
"Argument " + LQUOTE + arg + RQUOTE +
" failed to parse") {}
438 template <
typename T>
439 void throw_or_mimic(
const std::string& text) {
441 std::is_base_of<std::exception, T>::value,
442 "throw_or_mimic only works on std::exception and "
446#ifndef CXXOPTS_NO_EXCEPTIONS
453 std::cerr << exception.what() << std::endl;
454 std::exit(EXIT_FAILURE);
458 using OptionNames = std::vector<std::string>;
462 namespace parser_tool {
465 std::string negative =
"";
466 std::string base =
"";
467 std::string value =
"";
471 std::string arg_name =
"";
472 bool grouping =
false;
473 bool set_value =
false;
474 std::string value =
"";
477#ifdef CXXOPTS_NO_REGEX
478 inline IntegerDesc SplitInteger(
const std::string& text) {
480 throw_or_mimic<exceptions::incorrect_argument_type>(text);
483 const char* pdata = text.c_str();
488 if (strncmp(pdata,
"0x", 2) == 0) {
492 if (*pdata !=
'\0') {
493 desc.value = std::string(pdata);
495 throw_or_mimic<exceptions::incorrect_argument_type>(text);
500 inline bool IsTrueText(
const std::string& text) {
501 const char* pdata = text.c_str();
502 if (*pdata ==
't' || *pdata ==
'T') {
504 if (strncmp(pdata,
"rue\0", 4) == 0) {
507 }
else if (strncmp(pdata,
"1\0", 2) == 0) {
513 inline bool IsFalseText(
const std::string& text) {
514 const char* pdata = text.c_str();
515 if (*pdata ==
'f' || *pdata ==
'F') {
517 if (strncmp(pdata,
"alse\0", 5) == 0) {
520 }
else if (strncmp(pdata,
"0\0", 2) == 0) {
526 inline OptionNames split_option_names(
const std::string& text) {
527 OptionNames split_names;
529 std::string::size_type token_start_pos = 0;
530 auto length = text.length();
533 throw_or_mimic<exceptions::invalid_option_format>(text);
536 while (token_start_pos < length) {
537 const auto& npos = std::string::npos;
538 auto next_non_space_pos = text.find_first_not_of(
' ', token_start_pos);
539 if (next_non_space_pos == npos) {
540 throw_or_mimic<exceptions::invalid_option_format>(text);
542 token_start_pos = next_non_space_pos;
543 auto next_delimiter_pos = text.find(
',', token_start_pos);
544 if (next_delimiter_pos == token_start_pos) {
545 throw_or_mimic<exceptions::invalid_option_format>(text);
547 if (next_delimiter_pos == npos) {
548 next_delimiter_pos = length;
550 auto token_length = next_delimiter_pos - token_start_pos;
553 const char* option_name_valid_chars =
554 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
555 "abcdefghijklmnopqrstuvwxyz"
559 if (!std::isalnum(text[token_start_pos], std::locale::classic()) ||
560 text.find_first_not_of(option_name_valid_chars, token_start_pos) <
561 next_delimiter_pos) {
562 throw_or_mimic<exceptions::invalid_option_format>(text);
565 split_names.emplace_back(text.substr(token_start_pos, token_length));
566 token_start_pos = next_delimiter_pos + 1;
571 inline ArguDesc ParseArgument(
const char* arg,
bool& matched) {
573 const char* pdata = arg;
575 if (strncmp(pdata,
"--", 2) == 0) {
577 if (isalnum(*pdata, std::locale::classic())) {
578 argu_desc.arg_name.push_back(*pdata);
580 while (isalnum(*pdata, std::locale::classic()) || *pdata ==
'-' ||
582 argu_desc.arg_name.push_back(*pdata);
585 if (argu_desc.arg_name.length() > 1) {
587 argu_desc.set_value =
true;
589 if (*pdata !=
'\0') {
590 argu_desc.value = std::string(pdata);
593 }
else if (*pdata ==
'\0') {
598 }
else if (strncmp(pdata,
"-", 1) == 0) {
600 argu_desc.grouping =
true;
601 while (isalnum(*pdata, std::locale::classic())) {
602 argu_desc.arg_name.push_back(*pdata);
605 matched = !argu_desc.arg_name.empty() && *pdata ==
'\0';
614 std::basic_regex<char> integer_pattern(
"(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
616 std::basic_regex<char> truthy_pattern(
"(t|T)(rue)?|1");
618 std::basic_regex<char> falsy_pattern(
"(f|F)(alse)?|0");
620 std::basic_regex<char> option_matcher(
621 "--([[:alnum:]][-_[:alnum:]\\.]+)(=(.*))?|-([[:alnum:]].*)"
624 std::basic_regex<char> option_specifier(
625 "([[:alnum:]][-_[:alnum:]\\.]*)(,[ ]*[[:alnum:]][-_[:alnum:]]*)*"
628 std::basic_regex<char> option_specifier_separator(
", *");
632 inline IntegerDesc SplitInteger(
const std::string& text) {
634 std::regex_match(text, match, integer_pattern);
636 if (match.length() == 0) {
637 throw_or_mimic<exceptions::incorrect_argument_type>(text);
641 desc.negative = match[1];
642 desc.base = match[2];
643 desc.value = match[3];
645 if (match.length(4) > 0) {
646 desc.base = match[5];
654 inline bool IsTrueText(
const std::string& text) {
656 std::regex_match(text, result, truthy_pattern);
657 return !result.empty();
660 inline bool IsFalseText(
const std::string& text) {
662 std::regex_match(text, result, falsy_pattern);
663 return !result.empty();
669 inline OptionNames split_option_names(
const std::string& text) {
670 if (!std::regex_match(text.c_str(), option_specifier)) {
671 throw_or_mimic<exceptions::invalid_option_format>(text);
674 OptionNames split_names;
676 constexpr int use_non_matches{-1};
677 auto token_iterator = std::sregex_token_iterator(
680 option_specifier_separator,
685 std::sregex_token_iterator(),
686 std::back_inserter(split_names)
691 inline ArguDesc ParseArgument(
const char* arg,
bool& matched) {
692 std::match_results<const char*> result;
693 std::regex_match(arg, result, option_matcher);
694 matched = !result.empty();
698 argu_desc.arg_name = result[1].str();
699 argu_desc.set_value = result[2].length() > 0;
700 argu_desc.value = result[3].str();
701 if (result[4].length() > 0) {
702 argu_desc.grouping =
true;
703 argu_desc.arg_name = result[4].str();
711#undef CXXOPTS_NO_REGEX
716 template <
typename T,
bool B>
719 template <
typename T>
721 template <
typename U>
722 void operator()(
bool negative, U u,
const std::string& text) {
724 if (u >
static_cast<U
>((std::numeric_limits<T>::min)())) {
725 throw_or_mimic<exceptions::incorrect_argument_type>(text);
728 if (u >
static_cast<U
>((std::numeric_limits<T>::max)())) {
729 throw_or_mimic<exceptions::incorrect_argument_type>(text);
735 template <
typename T>
737 template <
typename U>
738 void operator()(
bool, U,
const std::string&)
const {}
741 template <
typename T,
typename U>
742 void check_signed_range(
bool negative, U value,
const std::string& text) {
748 template <
typename R,
typename T>
749 void checked_negate(R& r, T&& t,
const std::string&, std::true_type) {
753 r =
static_cast<R
>(-
static_cast<R
>(t - 1) - 1);
756 template <
typename R,
typename T>
757 void checked_negate(R&, T&&,
const std::string& text, std::false_type) {
758 throw_or_mimic<exceptions::incorrect_argument_type>(text);
761 template <
typename T>
762 void integer_parser(
const std::string& text, T& value) {
763 parser_tool::IntegerDesc int_desc = parser_tool::SplitInteger(text);
765 using US =
typename std::make_unsigned<T>::type;
766 constexpr bool is_signed = std::numeric_limits<T>::is_signed;
768 const bool negative = int_desc.negative.length() > 0;
769 const uint8_t base = int_desc.base.length() > 0 ? 16 : 10;
770 const std::string& value_match = int_desc.value;
774 for (
char ch : value_match) {
777 if (ch >=
'0' && ch <=
'9') {
778 digit =
static_cast<US
>(ch -
'0');
779 }
else if (base == 16 && ch >=
'a' && ch <=
'f') {
780 digit =
static_cast<US
>(ch -
'a' + 10);
781 }
else if (base == 16 && ch >=
'A' && ch <=
'F') {
782 digit =
static_cast<US
>(ch -
'A' + 10);
784 throw_or_mimic<exceptions::incorrect_argument_type>(text);
787 const US next =
static_cast<US
>(result * base + digit);
789 throw_or_mimic<exceptions::incorrect_argument_type>(text);
795 detail::check_signed_range<T>(negative, result, text);
798 checked_negate<T>(value, result, text, std::integral_constant<bool, is_signed>());
800 value =
static_cast<T
>(result);
804 template <
typename T>
805 void stringstream_parser(
const std::string& text, T& value) {
806 std::stringstream in(text);
809 throw_or_mimic<exceptions::incorrect_argument_type>(text);
813 template <typename T, typename std::enable_if<std::is_integral<T>::value>::type* =
nullptr>
814 void parse_value(
const std::string& text, T& value) {
815 integer_parser(text, value);
818 inline void parse_value(
const std::string& text,
bool& value) {
819 if (parser_tool::IsTrueText(text)) {
824 if (parser_tool::IsFalseText(text)) {
829 throw_or_mimic<exceptions::incorrect_argument_type>(text);
832 inline void parse_value(
const std::string& text, std::string& value) {
839 template <typename T, typename std::enable_if<!std::is_integral<T>::value>::type* =
nullptr>
840 void parse_value(
const std::string& text, T& value) {
841 stringstream_parser(text, value);
844 template <
typename T>
845 void parse_value(
const std::string& text, std::vector<T>& value) {
848 parse_value(text, v);
849 value.emplace_back(std::move(v));
852 std::stringstream in(text);
854 while (!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
856 parse_value(token, v);
857 value.emplace_back(std::move(v));
861#ifdef CXXOPTS_HAS_OPTIONAL
862 template <
typename T>
863 void parse_value(
const std::string& text, std::optional<T>& value) {
865 parse_value(text, result);
866 value = std::move(result);
870 inline void parse_value(
const std::string& text,
char& c) {
871 if (text.length() != 1) {
872 throw_or_mimic<exceptions::incorrect_argument_type>(text);
878 template <
typename T>
880 static constexpr bool value =
false;
883 template <
typename T>
885 static constexpr bool value =
true;
888 template <
typename T>
893 abstract_value() : m_result(std::make_shared<T>()), m_store(m_result.get()) {}
903 m_result = std::make_shared<T>();
904 m_store = m_result.get();
906 m_store = rhs.m_store;
909 m_default = rhs.m_default;
910 m_implicit = rhs.m_implicit;
911 m_default_value = rhs.m_default_value;
912 m_implicit_value = rhs.m_implicit_value;
915 void parse(
const std::string& text)
const override {
916 parse_value(text, *m_store);
919 bool is_container()
const override {
923 void parse()
const override {
924 parse_value(m_default_value, *m_store);
927 bool has_default()
const override {
931 bool has_implicit()
const override {
935 std::shared_ptr<Value> default_value(
const std::string& value)
override {
937 m_default_value = value;
938 return shared_from_this();
941 std::shared_ptr<Value> implicit_value(
const std::string& value)
override {
943 m_implicit_value = value;
944 return shared_from_this();
947 std::shared_ptr<Value> no_implicit_value()
override {
949 return shared_from_this();
952 std::string get_default_value()
const override {
953 return m_default_value;
956 std::string get_implicit_value()
const override {
957 return m_implicit_value;
960 bool is_boolean()
const override {
961 return std::is_same<T, bool>::value;
964 const T& get()
const {
965 if (m_store ==
nullptr) {
972 std::shared_ptr<T> m_result{};
975 bool m_default =
false;
976 bool m_implicit =
false;
978 std::string m_default_value{};
979 std::string m_implicit_value{};
982 template <
typename T>
988 std::shared_ptr<Value> clone()
const override {
989 return std::make_shared<standard_value<T>>(*this);
999 set_default_and_implicit();
1004 m_implicit_value =
"true";
1007 std::shared_ptr<Value> clone()
const override {
1008 return std::make_shared<standard_value<bool>>(*this);
1012 void set_default_and_implicit() {
1014 m_default_value =
"false";
1016 m_implicit_value =
"true";
1022 template <
typename T>
1023 std::shared_ptr<Value> value() {
1024 return std::make_shared<values::standard_value<T>>();
1027 template <
typename T>
1028 std::shared_ptr<Value> value(T& t) {
1029 return std::make_shared<values::standard_value<T>>(&t);
1035 inline const std::string& first_or_empty(
const OptionNames& long_names) {
1036 static const std::string empty{
""};
1037 return long_names.empty() ? empty : long_names.front();
1043 std::string short_, OptionNames long_, String desc, std::shared_ptr<const Value> val
1045 : m_short(std::move(short_)),
1046 m_long(std::move(long_)),
1047 m_desc(std::move(desc)),
1048 m_value(std::move(val)),
1050 m_hash = std::hash<std::string>{}(first_long_name() + m_short);
1054 : m_desc(rhs.m_desc), m_value(rhs.m_value->clone()), m_count(rhs.m_count) {}
1059 const String& description()
const {
1064 const Value& value()
const {
1069 std::shared_ptr<Value> make_storage()
const {
1070 return m_value->clone();
1074 const std::string& short_name()
const {
1079 const std::string& first_long_name()
const {
1080 return first_or_empty(m_long);
1084 const std::string& essential_name()
const {
1085 return m_long.empty() ? m_short : m_long.front();
1089 const OptionNames& long_names()
const {
1093 std::size_t hash()
const {
1098 std::string m_short{};
1099 OptionNames m_long{};
1101 std::shared_ptr<const Value> m_value{};
1104 std::size_t m_hash{};
1112 std::string default_value;
1114 std::string implicit_value;
1115 std::string arg_help;
1122 std::string description{};
1123 std::vector<HelpOptionDetails> options{};
1128 void parse(
const std::shared_ptr<const OptionDetails>& details,
const std::string& text) {
1129 ensure_value(details);
1131 m_value->parse(text);
1132 m_long_names = &details->long_names();
1135 void parse_default(
const std::shared_ptr<const OptionDetails>& details) {
1136 ensure_value(details);
1138 m_long_names = &details->long_names();
1142 void parse_no_value(
const std::shared_ptr<const OptionDetails>& details) {
1143 m_long_names = &details->long_names();
1146#if defined(CXXOPTS_NULL_DEREF_IGNORE)
1147 CXXOPTS_DIAGNOSTIC_PUSH
1148 CXXOPTS_IGNORE_WARNING(
"-Wnull-dereference")
1152 std::size_t count()
const noexcept {
1156#if defined(CXXOPTS_NULL_DEREF_IGNORE)
1157 CXXOPTS_DIAGNOSTIC_POP
1162 bool has_default()
const noexcept {
1166 template <
typename T>
1167 const T& as()
const {
1168 if (m_value ==
nullptr) {
1169 throw_or_mimic<exceptions::option_has_no_value>(
1170 m_long_names ==
nullptr ?
"" : first_or_empty(*m_long_names)
1174 return CXXOPTS_RTTI_CAST<const values::standard_value<T>&>(*m_value).get();
1178 void ensure_value(
const std::shared_ptr<const OptionDetails>& details) {
1179 if (m_value ==
nullptr) {
1180 m_value = details->make_storage();
1184 const OptionNames* m_long_names =
nullptr;
1187 std::shared_ptr<Value> m_value{};
1188 std::size_t m_count = 0;
1189 bool m_default =
false;
1194 KeyValue(std::string key_, std::string value_)
1195 : m_key(std::move(key_)), m_value(std::move(value_)) {}
1198 const std::string& key()
const {
1203 const std::string& value()
const {
1207 template <
typename T>
1210 values::parse_value(m_value, result);
1216 std::string m_value;
1219 using ParsedHashMap = std::unordered_map<std::size_t, OptionValue>;
1220 using NameHashMap = std::unordered_map<std::string, std::size_t>;
1226 using iterator_category = std::forward_iterator_tag;
1228 using difference_type = void;
1237 CXXOPTS_DIAGNOSTIC_PUSH
1238 CXXOPTS_IGNORE_WARNING(
"-Weffc++")
1242 m_sequential =
false;
1243 m_iter = m_pr->m_defaults.end();
1245 m_sequential =
true;
1246 m_iter = m_pr->m_sequential.begin();
1248 if (m_iter == m_pr->m_sequential.end()) {
1249 m_sequential =
false;
1250 m_iter = m_pr->m_defaults.begin();
1255 CXXOPTS_DIAGNOSTIC_POP
1259 if (m_sequential && m_iter == m_pr->m_sequential.end()) {
1260 m_sequential =
false;
1261 m_iter = m_pr->m_defaults.begin();
1273 bool operator==(
const Iterator& other)
const {
1274 return (m_sequential == other.m_sequential) && (m_iter == other.m_iter);
1277 bool operator!=(
const Iterator& other)
const {
1278 return !(*
this == other);
1286 return m_iter.operator->();
1291 std::vector<KeyValue>::const_iterator m_iter;
1292 bool m_sequential =
true;
1299 NameHashMap&& keys, ParsedHashMap&& values, std::vector<KeyValue> sequential,
1300 std::vector<KeyValue> default_opts, std::vector<std::string>&& unmatched_args
1302 : m_keys(std::move(keys)),
1303 m_values(std::move(values)),
1304 m_sequential(std::move(sequential)),
1305 m_defaults(std::move(default_opts)),
1306 m_unmatched(std::move(unmatched_args)) {}
1311 Iterator begin()
const {
1312 return Iterator(
this);
1315 Iterator end()
const {
1316 return Iterator(
this,
true);
1319 std::size_t count(
const std::string& o)
const {
1320 auto iter = m_keys.find(o);
1321 if (iter == m_keys.end()) {
1325 auto viter = m_values.find(iter->second);
1327 if (viter == m_values.end()) {
1331 return viter->second.count();
1334 const OptionValue& operator[](
const std::string& option)
const {
1335 auto iter = m_keys.find(option);
1337 if (iter == m_keys.end()) {
1338 throw_or_mimic<exceptions::requested_option_not_present>(option);
1341 auto viter = m_values.find(iter->second);
1343 if (viter == m_values.end()) {
1344 throw_or_mimic<exceptions::requested_option_not_present>(option);
1347 return viter->second;
1350 const std::vector<KeyValue>& arguments()
const {
1351 return m_sequential;
1354 const std::vector<std::string>& unmatched()
const {
1358 const std::vector<KeyValue>& defaults()
const {
1362 const std::string arguments_string()
const {
1364 for (
const auto& kv : m_sequential) {
1365 result += kv.key() +
" = " + kv.value() +
"\n";
1367 for (
const auto& kv : m_defaults) {
1368 result += kv.key() +
" = " + kv.value() +
" " +
"(default)" +
"\n";
1374 NameHashMap m_keys{};
1375 ParsedHashMap m_values{};
1376 std::vector<KeyValue> m_sequential{};
1377 std::vector<KeyValue> m_defaults{};
1378 std::vector<std::string> m_unmatched{};
1383 std::string opts, std::string desc,
1384 std::shared_ptr<const Value> value = ::cxxopts::value<bool>(), std::string arg_help =
""
1386 : opts_(std::move(opts)),
1387 desc_(std::move(desc)),
1388 value_(std::move(value)),
1389 arg_help_(std::move(arg_help)) {}
1393 std::shared_ptr<const Value> value_;
1394 std::string arg_help_;
1397 using OptionMap = std::unordered_map<std::string, std::shared_ptr<OptionDetails>>;
1398 using PositionalList = std::vector<std::string>;
1399 using PositionalListIterator = PositionalList::const_iterator;
1404 const OptionMap& options,
const PositionalList& positional,
bool allow_unrecognised
1406 : m_options(options),
1407 m_positional(positional),
1408 m_allow_unrecognised(allow_unrecognised) {}
1410 ParseResult parse(
int argc,
const char*
const* argv);
1412 bool consume_positional(
const std::string& a, PositionalListIterator& next);
1414 void checked_parse_arg(
1415 int argc,
const char*
const* argv,
int& current,
1416 const std::shared_ptr<OptionDetails>& value,
const std::string& name
1420 OptionMap::const_iterator iter,
const std::string& option,
const std::string& arg
1424 const std::shared_ptr<OptionDetails>& value,
const std::string& name,
1425 const std::string& arg =
""
1428 void parse_default(
const std::shared_ptr<OptionDetails>& details);
1430 void parse_no_value(
const std::shared_ptr<OptionDetails>& details);
1433 void finalise_aliases();
1435 const OptionMap& m_options;
1436 const PositionalList& m_positional;
1438 std::vector<KeyValue> m_sequential{};
1439 std::vector<KeyValue> m_defaults{};
1440 bool m_allow_unrecognised;
1442 ParsedHashMap m_parsed{};
1443 NameHashMap m_keys{};
1448 explicit Options(std::string program_name, std::string help_string =
"")
1449 : m_program(std::move(program_name)),
1450 m_help_string(toLocalString(std::move(help_string))),
1451 m_custom_help(
"[OPTION...]"),
1452 m_positional_help(
"positional parameters"),
1453 m_show_positional(
false),
1454 m_allow_unrecognised(
false),
1456 m_tab_expansion(
false),
1457 m_options(std::make_shared<OptionMap>()) {}
1459 Options& positional_help(std::string help_text) {
1460 m_positional_help = std::move(help_text);
1464 Options& custom_help(std::string help_text) {
1465 m_custom_help = std::move(help_text);
1469 Options& show_positional_help() {
1470 m_show_positional =
true;
1474 Options& allow_unrecognised_options() {
1475 m_allow_unrecognised =
true;
1479 Options& set_width(std::size_t width) {
1484 Options& set_tab_expansion(
bool expansion =
true) {
1485 m_tab_expansion = expansion;
1489 ParseResult parse(
int argc,
const char*
const* argv);
1493 void add_options(
const std::string& group, std::initializer_list<Option> options);
1495 void add_option(
const std::string& group,
const Option& option);
1498 const std::string& group,
const std::string& s,
const OptionNames& l, std::string desc,
1499 const std::shared_ptr<const Value>& value, std::string arg_help
1503 const std::string& group,
const std::string& short_name,
1504 const std::string& single_long_name, std::string desc,
1505 const std::shared_ptr<const Value>& value, std::string arg_help
1507 OptionNames long_names;
1508 long_names.emplace_back(single_long_name);
1509 add_option(group, short_name, long_names, desc, value, arg_help);
1513 void parse_positional(std::string option);
1515 void parse_positional(std::vector<std::string> options);
1517 void parse_positional(std::initializer_list<std::string> options);
1519 template <
typename Iterator>
1520 void parse_positional(Iterator begin, Iterator end) {
1521 parse_positional(std::vector<std::string>{begin, end});
1524 std::string help(
const std::vector<std::string>& groups = {},
bool print_usage =
true)
1527 std::vector<std::string> groups()
const;
1531 const std::string& program()
const {
1536 void add_one_option(
1537 const std::string& option,
const std::shared_ptr<OptionDetails>& details
1540 String help_one_group(
const std::string& group)
const;
1542 void generate_group_help(String& result,
const std::vector<std::string>& groups)
const;
1544 void generate_all_groups_help(String& result)
const;
1546 std::string m_program{};
1547 String m_help_string{};
1548 std::string m_custom_help{};
1549 std::string m_positional_help{};
1550 bool m_show_positional;
1551 bool m_allow_unrecognised;
1552 std::size_t m_width;
1553 bool m_tab_expansion;
1555 std::shared_ptr<OptionMap> m_options;
1556 std::vector<std::string> m_positional{};
1557 std::unordered_set<std::string> m_positional_set{};
1560 std::map<std::string, HelpGroupDetails> m_help{};
1566 : m_options(options), m_group(std::move(group)) {}
1569 const std::string& opts,
const std::string& desc,
1570 const std::shared_ptr<const Value>& value = ::cxxopts::value<bool>(),
1571 std::string arg_help =
""
1576 std::string m_group;
1580 constexpr std::size_t OPTION_LONGEST = 30;
1581 constexpr std::size_t OPTION_DESC_GAP = 2;
1584 const auto& s = o.s;
1585 const auto& l = first_or_empty(o.l);
1587 String result =
" ";
1590 result +=
"-" + toLocalString(s);
1599 result +=
" --" + toLocalString(l);
1602 auto arg = !o.arg_help.empty() ? toLocalString(o.arg_help) :
"arg";
1604 if (!o.is_boolean) {
1605 if (o.has_implicit) {
1606 result +=
" [=" + arg +
"(=" + toLocalString(o.implicit_value) +
")]";
1608 result +=
" " + arg;
1615 String format_description(
1616 const HelpOptionDetails& o, std::size_t start, std::size_t allowed,
bool tab_expansion
1620 if (o.has_default && (!o.is_boolean || o.default_value !=
"false")) {
1621 if (!o.default_value.empty()) {
1622 desc += toLocalString(
" (default: " + o.default_value +
")");
1624 desc += toLocalString(
" (default: \"\")");
1630 if (tab_expansion) {
1632 auto size = std::size_t{0};
1633 for (
auto c = std::begin(desc); c != std::end(desc); ++c) {
1637 }
else if (*c ==
'\t') {
1638 auto skip = 8 - size % 8;
1639 stringAppend(desc2, skip,
' ');
1651 auto current = std::begin(desc);
1652 auto previous = current;
1653 auto startLine = current;
1654 auto lastSpace = current;
1656 auto size = std::size_t{};
1659 bool onlyWhiteSpace =
true;
1661 while (current != std::end(desc)) {
1662 appendNewLine =
false;
1663 if (*previous ==
' ' || *previous ==
'\t') {
1664 lastSpace = current;
1666 if (*current !=
' ' && *current !=
'\t') {
1667 onlyWhiteSpace =
false;
1670 while (*current ==
'\n') {
1673 appendNewLine =
true;
1676 if (!appendNewLine && size >= allowed) {
1677 if (lastSpace != startLine) {
1678 current = lastSpace;
1681 appendNewLine =
true;
1684 if (appendNewLine) {
1685 stringAppend(result, startLine, current);
1686 startLine = current;
1687 lastSpace = current;
1689 if (*previous !=
'\n') {
1690 stringAppend(result,
"\n");
1693 stringAppend(result, start,
' ');
1695 if (*previous !=
'\n') {
1696 stringAppend(result, lastSpace, current);
1699 onlyWhiteSpace =
true;
1709 if (!onlyWhiteSpace) {
1710 stringAppend(result, startLine, previous);
1718 inline void Options::add_options(
1719 const std::string& group, std::initializer_list<Option> options
1721 OptionAdder option_adder(*
this, group);
1722 for (
const auto& option : options) {
1723 option_adder(option.opts_, option.desc_, option.value_, option.arg_help_);
1727 inline OptionAdder Options::add_options(std::string group) {
1728 return OptionAdder(*
this, std::move(group));
1731 inline OptionAdder& OptionAdder::operator()(
1732 const std::string& opts,
const std::string& desc,
const std::shared_ptr<const Value>& value,
1733 std::string arg_help
1735 OptionNames option_names = values::parser_tool::split_option_names(opts);
1738 std::string short_name{
""};
1739 auto first_short_name_iter =
1740 std::partition(option_names.begin(), option_names.end(), [&](
const std::string& name) {
1741 return name.length() > 1;
1743 auto num_length_1_names = (option_names.end() - first_short_name_iter);
1744 switch (num_length_1_names) {
1746 short_name = *first_short_name_iter;
1747 option_names.erase(first_short_name_iter);
1751 throw_or_mimic<exceptions::invalid_option_format>(opts);
1754 m_options.add_option(m_group, short_name, option_names, desc, value, std::move(arg_help));
1759 inline void OptionParser::parse_default(
const std::shared_ptr<OptionDetails>& details) {
1761 auto& store = m_parsed[details->hash()];
1762 store.parse_default(details);
1763 m_defaults.emplace_back(details->essential_name(), details->value().get_default_value());
1766 inline void OptionParser::parse_no_value(
const std::shared_ptr<OptionDetails>& details) {
1767 auto& store = m_parsed[details->hash()];
1768 store.parse_no_value(details);
1771 inline void OptionParser::parse_option(
1772 const std::shared_ptr<OptionDetails>& value,
const std::string& ,
1773 const std::string& arg
1775 auto hash = value->hash();
1776 auto& result = m_parsed[hash];
1777 result.parse(value, arg);
1779 m_sequential.emplace_back(value->essential_name(), arg);
1782 inline void OptionParser::checked_parse_arg(
1783 int argc,
const char*
const* argv,
int& current,
1784 const std::shared_ptr<OptionDetails>& value,
const std::string& name
1786 if (current + 1 >= argc) {
1787 if (value->value().has_implicit()) {
1788 parse_option(value, name, value->value().get_implicit_value());
1790 throw_or_mimic<exceptions::missing_argument>(name);
1793 if (value->value().has_implicit()) {
1794 parse_option(value, name, value->value().get_implicit_value());
1796 parse_option(value, name, argv[current + 1]);
1802 inline void OptionParser::add_to_option(
1803 OptionMap::const_iterator iter,
const std::string& option,
const std::string& arg
1805 parse_option(iter->second, option, arg);
1808 inline bool OptionParser::consume_positional(
1809 const std::string& a, PositionalListIterator& next
1811 while (next != m_positional.end()) {
1812 auto iter = m_options.find(*next);
1813 if (iter != m_options.end()) {
1814 if (!iter->second->value().is_container()) {
1815 auto& result = m_parsed[iter->second->hash()];
1816 if (result.count() == 0) {
1817 add_to_option(iter, *next, a);
1824 add_to_option(iter, *next, a);
1827 throw_or_mimic<exceptions::no_such_option>(*next);
1833 inline void Options::parse_positional(std::string option) {
1834 parse_positional(std::vector<std::string>{std::move(option)});
1837 inline void Options::parse_positional(std::vector<std::string> options) {
1838 m_positional = std::move(options);
1840 m_positional_set.insert(m_positional.begin(), m_positional.end());
1843 inline void Options::parse_positional(std::initializer_list<std::string> options) {
1844 parse_positional(std::vector<std::string>(options));
1847 inline ParseResult Options::parse(
int argc,
const char*
const* argv) {
1848 OptionParser parser(*m_options, m_positional, m_allow_unrecognised);
1850 return parser.parse(argc, argv);
1853 inline ParseResult OptionParser::parse(
int argc,
const char*
const* argv) {
1855 bool consume_remaining =
false;
1856 auto next_positional = m_positional.begin();
1858 std::vector<std::string> unmatched;
1860 while (current != argc) {
1861 if (strcmp(argv[current],
"--") == 0) {
1862 consume_remaining =
true;
1866 bool matched =
false;
1867 values::parser_tool::ArguDesc argu_desc =
1868 values::parser_tool::ParseArgument(argv[current], matched);
1874 if (argv[current][0] ==
'-' && argv[current][1] !=
'\0') {
1875 if (!m_allow_unrecognised) {
1876 throw_or_mimic<exceptions::invalid_option_syntax>(argv[current]);
1882 if (consume_positional(argv[current], next_positional)) {
1884 unmatched.emplace_back(argv[current]);
1889 if (argu_desc.grouping) {
1890 const std::string& s = argu_desc.arg_name;
1892 for (std::size_t i = 0; i != s.size(); ++i) {
1893 std::string name(1, s[i]);
1894 auto iter = m_options.find(name);
1896 if (iter == m_options.end()) {
1897 if (m_allow_unrecognised) {
1898 unmatched.push_back(std::string(
"-") + s[i]);
1902 throw_or_mimic<exceptions::no_such_option>(name);
1905 auto value = iter->second;
1907 if (i + 1 == s.size()) {
1909 checked_parse_arg(argc, argv, current, value, name);
1910 }
else if (value->value().has_implicit()) {
1911 parse_option(value, name, value->value().get_implicit_value());
1912 }
else if (i + 1 < s.size()) {
1913 std::string arg_value = s.substr(i + 1);
1914 parse_option(value, name, arg_value);
1918 throw_or_mimic<exceptions::option_requires_argument>(name);
1921 }
else if (argu_desc.arg_name.length() != 0) {
1922 const std::string& name = argu_desc.arg_name;
1924 auto iter = m_options.find(name);
1926 if (iter == m_options.end()) {
1927 if (m_allow_unrecognised) {
1929 unmatched.emplace_back(argv[current]);
1934 throw_or_mimic<exceptions::no_such_option>(name);
1937 auto opt = iter->second;
1940 if (argu_desc.set_value) {
1943 parse_option(opt, name, argu_desc.value);
1946 checked_parse_arg(argc, argv, current, opt, name);
1954 for (
auto& opt : m_options) {
1955 auto& detail = opt.second;
1956 const auto& value = detail->value();
1958 auto& store = m_parsed[detail->hash()];
1960 if (value.has_default()) {
1961 if (!store.count() && !store.has_default()) {
1962 parse_default(detail);
1965 parse_no_value(detail);
1969 if (consume_remaining) {
1970 while (current < argc) {
1971 if (!consume_positional(argv[current], next_positional)) {
1978 while (current != argc) {
1979 unmatched.emplace_back(argv[current]);
1988 std::move(m_parsed),
1989 std::move(m_sequential),
1990 std::move(m_defaults),
1991 std::move(unmatched)
1996 inline void OptionParser::finalise_aliases() {
1997 for (
auto& option : m_options) {
1998 auto& detail = *option.second;
1999 auto hash = detail.hash();
2000 m_keys[detail.short_name()] = hash;
2001 for (
const auto& long_name : detail.long_names()) {
2002 m_keys[long_name] = hash;
2005 m_parsed.emplace(hash, OptionValue());
2009 inline void Options::add_option(
const std::string& group,
const Option& option) {
2010 add_options(group, {option});
2013 inline void Options::add_option(
2014 const std::string& group,
const std::string& s,
const OptionNames& l, std::string desc,
2015 const std::shared_ptr<const Value>& value, std::string arg_help
2017 auto stringDesc = toLocalString(std::move(desc));
2018 auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);
2021 add_one_option(s, option);
2024 for (
const auto& long_name : l) {
2025 add_one_option(long_name, option);
2029 auto& options = m_help[group];
2031 options.options.emplace_back(HelpOptionDetails{
2035 value->has_default(),
2036 value->get_default_value(),
2037 value->has_implicit(),
2038 value->get_implicit_value(),
2039 std::move(arg_help),
2040 value->is_container(),
2041 value->is_boolean()});
2044 inline void Options::add_one_option(
2045 const std::string& option,
const std::shared_ptr<OptionDetails>& details
2047 auto in = m_options->emplace(option, details);
2050 throw_or_mimic<exceptions::option_already_exists>(option);
2054 inline String Options::help_one_group(
const std::string& g)
const {
2055 using OptionHelp = std::vector<std::pair<String, String>>;
2057 auto group = m_help.find(g);
2058 if (group == m_help.end()) {
2064 std::size_t longest = 0;
2069 result += toLocalString(
" " + g +
" options:\n");
2072 for (
const auto& o : group->second.options) {
2073 if (o.l.size() && m_positional_set.find(o.l.front()) != m_positional_set.end() &&
2074 !m_show_positional) {
2078 auto s = format_option(o);
2079 longest = (std::max)(longest, stringLength(s));
2080 format.push_back(std::make_pair(s, String()));
2082 longest = (std::min)(longest, OPTION_LONGEST);
2085 std::size_t allowed = 10;
2086 if (m_width > allowed + longest + OPTION_DESC_GAP) {
2087 allowed = m_width - longest - OPTION_DESC_GAP;
2090 auto fiter = format.begin();
2091 for (
const auto& o : group->second.options) {
2092 if (o.l.size() && m_positional_set.find(o.l.front()) != m_positional_set.end() &&
2093 !m_show_positional) {
2097 auto d = format_description(o, longest + OPTION_DESC_GAP, allowed, m_tab_expansion);
2099 result += fiter->first;
2100 if (stringLength(fiter->first) > longest) {
2102 result += toLocalString(std::string(longest + OPTION_DESC_GAP,
' '));
2104 result += toLocalString(
2105 std::string(longest + OPTION_DESC_GAP - stringLength(fiter->first),
' ')
2117 inline void Options::generate_group_help(
2118 String& result,
const std::vector<std::string>& print_groups
2120 for (std::size_t i = 0; i != print_groups.size(); ++i) {
2121 const String& group_help_text = help_one_group(print_groups[i]);
2122 if (empty(group_help_text)) {
2125 result += group_help_text;
2126 if (i < print_groups.size() - 1) {
2132 inline void Options::generate_all_groups_help(String& result)
const {
2133 std::vector<std::string> all_groups;
2138 std::back_inserter(all_groups),
2139 [](
const std::map<std::string, HelpGroupDetails>::value_type& group) {
2144 generate_group_help(result, all_groups);
2147 inline std::string Options::help(
const std::vector<std::string>& help_groups,
bool print_usage)
2149 String result = m_help_string;
2151 result +=
"\nUsage:\n " + toLocalString(m_program);
2154 if (!m_custom_help.empty()) {
2155 result +=
" " + toLocalString(m_custom_help);
2158 if (!m_positional.empty() && !m_positional_help.empty()) {
2159 result +=
" " + toLocalString(m_positional_help);
2164 if (help_groups.empty()) {
2165 generate_all_groups_help(result);
2167 generate_group_help(result, help_groups);
2170 return toUTF8String(result);
2173 inline std::vector<std::string> Options::groups()
const {
2174 std::vector<std::string> g;
2179 std::back_inserter(g),
2180 [](
const std::map<std::string, HelpGroupDetails>::value_type& pair) {
2188 inline const HelpGroupDetails& Options::group_help(
const std::string& group)
const {
2189 return m_help.at(group);
2197#pragma GCC diagnostic pop
Definition cxxopts.hpp:1192
Definition cxxopts.hpp:1563
Definition cxxopts.hpp:1040
Definition cxxopts.hpp:1401
Definition cxxopts.hpp:1126
Definition cxxopts.hpp:1446
Definition cxxopts.hpp:1224
Definition cxxopts.hpp:1222
Definition cxxopts.hpp:311
Definition cxxopts.hpp:344
Definition cxxopts.hpp:406
Definition cxxopts.hpp:430
Definition cxxopts.hpp:379
Definition cxxopts.hpp:394
Definition cxxopts.hpp:388
Definition cxxopts.hpp:367
Definition cxxopts.hpp:421
Definition cxxopts.hpp:400
Definition cxxopts.hpp:362
Definition cxxopts.hpp:415
Definition cxxopts.hpp:357
Definition cxxopts.hpp:889
Definition cxxopts.hpp:983
Definition cxxopts.hpp:1120
Definition cxxopts.hpp:1107
Definition cxxopts.hpp:1381
Definition cxxopts.hpp:717
Definition cxxopts.hpp:879