27#ifndef CXXOPTS_HPP_INCLUDED
28#define CXXOPTS_HPP_INCLUDED
35#include <initializer_list>
40#include <unordered_map>
41#include <unordered_set>
47#ifdef CXXOPTS_NO_EXCEPTIONS
51#if defined(__GNUC__) && !defined(__clang__)
52# if (__GNUC__ * 10 + __GNUC_MINOR__) < 49
53# define CXXOPTS_NO_REGEX true
56#if defined(_MSC_VER) && !defined(__clang__)
57#define CXXOPTS_LINKONCE_CONST __declspec(selectany) extern
58#define CXXOPTS_LINKONCE __declspec(selectany) extern
60#define CXXOPTS_LINKONCE_CONST
61#define CXXOPTS_LINKONCE
64#ifndef CXXOPTS_NO_REGEX
70# if __has_include(<optional>)
72# ifdef __cpp_lib_optional
73# define CXXOPTS_HAS_OPTIONAL
76# if __has_include(<filesystem>)
78# ifdef __cpp_lib_filesystem
79# define CXXOPTS_HAS_FILESYSTEM
84#define CXXOPTS_FALLTHROUGH
85#ifdef __has_cpp_attribute
86 #if __has_cpp_attribute(fallthrough)
87 #undef CXXOPTS_FALLTHROUGH
88 #define CXXOPTS_FALLTHROUGH [[fallthrough]]
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 3
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
129static constexpr struct {
130 uint8_t major, minor, patch;
132 CXXOPTS__VERSION_MAJOR,
133 CXXOPTS__VERSION_MINOR,
134 CXXOPTS__VERSION_PATCH
144#ifdef CXXOPTS_USE_UNICODE
145#include <unicode/unistr.h>
149using String = icu::UnicodeString;
153toLocalString(std::string s)
155 return icu::UnicodeString::fromUTF8(std::move(s));
160CXXOPTS_DIAGNOSTIC_PUSH
161CXXOPTS_IGNORE_WARNING(
"-Wnon-virtual-dtor")
163class UnicodeStringIterator
167 using iterator_category = std::forward_iterator_tag;
168 using value_type = int32_t;
169 using difference_type = std::ptrdiff_t;
170 using pointer = value_type*;
171 using reference = value_type&;
173 UnicodeStringIterator(
const icu::UnicodeString*
string, int32_t pos)
182 return s->char32At(i);
186 operator==(
const UnicodeStringIterator& rhs)
const
188 return s == rhs.s && i == rhs.i;
192 operator!=(
const UnicodeStringIterator& rhs)
const
194 return !(*
this == rhs);
197 UnicodeStringIterator&
204 UnicodeStringIterator
207 return UnicodeStringIterator(s, i + v);
211 const icu::UnicodeString* s;
214CXXOPTS_DIAGNOSTIC_POP
218stringAppend(String&s, String a)
220 return s.append(std::move(a));
225stringAppend(String& s, std::size_t n, UChar32 c)
227 for (std::size_t i = 0; i != n; ++i)
235template <
typename Iterator>
237stringAppend(String& s, Iterator begin, Iterator end)
250stringLength(
const String& s)
252 return static_cast<size_t>(s.length());
257toUTF8String(
const String& s)
260 s.toUTF8String(result);
267empty(
const String& s)
277cxxopts::UnicodeStringIterator
278begin(
const icu::UnicodeString& s)
280 return cxxopts::UnicodeStringIterator(&s, 0);
284cxxopts::UnicodeStringIterator
285end(
const icu::UnicodeString& s)
287 return cxxopts::UnicodeStringIterator(&s, s.length());
297using String = std::string;
303 return std::forward<T>(t);
308stringLength(
const String& s)
315stringAppend(String&s,
const String& a)
322stringAppend(String& s, std::size_t n,
char c)
324 return s.append(n, c);
327template <
typename Iterator>
329stringAppend(String& s, Iterator begin, Iterator end)
331 return s.append(begin, end);
338 return std::forward<T>(t);
343empty(
const std::string& s)
356CXXOPTS_LINKONCE_CONST std::string LQUOTE(
"\'");
357CXXOPTS_LINKONCE_CONST std::string RQUOTE(
"\'");
364CXXOPTS_DIAGNOSTIC_PUSH
365CXXOPTS_IGNORE_WARNING(
"-Wnon-virtual-dtor")
368CXXOPTS_IGNORE_WARNING("-Weffc++")
373 virtual ~Value() =
default;
376 std::shared_ptr<Value>
380 add(
const std::string& text)
const = 0;
383 parse(
const std::string& text)
const = 0;
389 has_default()
const = 0;
392 is_container()
const = 0;
395 has_implicit()
const = 0;
398 get_default_value()
const = 0;
401 get_implicit_value()
const = 0;
403 virtual std::shared_ptr<Value>
404 default_value(
const std::string& value) = 0;
406 virtual std::shared_ptr<Value>
407 implicit_value(
const std::string& value) = 0;
409 virtual std::shared_ptr<Value>
410 no_implicit_value() = 0;
413 is_boolean()
const = 0;
416CXXOPTS_DIAGNOSTIC_POP
418namespace exceptions {
424 : m_message(std::move(message))
430 what()
const noexcept override
432 return m_message.c_str();
436 std::string m_message;
452 explicit parsing(
const std::string& message)
462 :
specification(
"Option " + LQUOTE + option + RQUOTE +
" already exists")
471 :
specification(
"Invalid option format " + LQUOTE + format + RQUOTE)
479 :
parsing(
"Argument " + LQUOTE + text + RQUOTE +
480 " starts with a - but has incorrect syntax")
489 :
parsing(
"Option " + LQUOTE + option + RQUOTE +
" does not exist")
499 "Option " + LQUOTE + option + RQUOTE +
" is missing an argument"
510 "Option " + LQUOTE + option + RQUOTE +
" requires an argument"
521 const std::string& option,
522 const std::string& arg
525 "Option " + LQUOTE + option + RQUOTE +
526 " does not take an argument, but argument " +
527 LQUOTE + arg + RQUOTE +
" given"
537 :
parsing(
"Option " + LQUOTE + option + RQUOTE +
" not present")
548 (
"Option " + LQUOTE + option + RQUOTE +
" has no value") :
549 "Option has no value")
559 const std::string& arg
562 "Argument " + LQUOTE + arg + RQUOTE +
" failed to parse"
572void throw_or_mimic(
const std::string& text)
574 static_assert(std::is_base_of<std::exception, T>::value,
575 "throw_or_mimic only works on std::exception and "
578#ifndef CXXOPTS_NO_EXCEPTIONS
585 std::cerr << exception.what() << std::endl;
586 std::exit(EXIT_FAILURE);
590using OptionNames = std::vector<std::string>;
594namespace parser_tool {
598 std::string negative =
"";
599 std::string base =
"";
600 std::string value =
"";
603 std::string arg_name =
"";
604 bool grouping =
false;
605 bool set_value =
false;
606 std::string value =
"";
609#ifdef CXXOPTS_NO_REGEX
610inline IntegerDesc SplitInteger(
const std::string &text)
614 throw_or_mimic<exceptions::incorrect_argument_type>(text);
617 const char *pdata = text.c_str();
623 if (strncmp(pdata,
"0x", 2) == 0)
630 desc.value = std::string(pdata);
634 throw_or_mimic<exceptions::incorrect_argument_type>(text);
639inline bool IsTrueText(
const std::string &text)
641 const char *pdata = text.c_str();
642 if (*pdata ==
't' || *pdata ==
'T')
645 if (strncmp(pdata,
"rue\0", 4) == 0)
650 else if (strncmp(pdata,
"1\0", 2) == 0)
657inline bool IsFalseText(
const std::string &text)
659 const char *pdata = text.c_str();
660 if (*pdata ==
'f' || *pdata ==
'F')
663 if (strncmp(pdata,
"alse\0", 5) == 0)
668 else if (strncmp(pdata,
"0\0", 2) == 0)
675inline OptionNames split_option_names(
const std::string &text)
677 OptionNames split_names;
679 std::string::size_type token_start_pos = 0;
680 auto length = text.length();
684 throw_or_mimic<exceptions::invalid_option_format>(text);
687 while (token_start_pos < length) {
688 const auto &npos = std::string::npos;
689 auto next_non_space_pos = text.find_first_not_of(
' ', token_start_pos);
690 if (next_non_space_pos == npos) {
691 throw_or_mimic<exceptions::invalid_option_format>(text);
693 token_start_pos = next_non_space_pos;
694 auto next_delimiter_pos = text.find(
',', token_start_pos);
695 if (next_delimiter_pos == token_start_pos) {
696 throw_or_mimic<exceptions::invalid_option_format>(text);
698 if (next_delimiter_pos == npos) {
699 next_delimiter_pos = length;
701 auto token_length = next_delimiter_pos - token_start_pos;
704 const char* option_name_valid_chars =
705 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
706 "abcdefghijklmnopqrstuvwxyz"
710 if (!std::isalnum(text[token_start_pos], std::locale::classic()) ||
711 text.find_first_not_of(option_name_valid_chars, token_start_pos) < next_delimiter_pos) {
712 throw_or_mimic<exceptions::invalid_option_format>(text);
715 split_names.emplace_back(text.substr(token_start_pos, token_length));
716 token_start_pos = next_delimiter_pos + 1;
721inline ArguDesc ParseArgument(
const char *arg,
bool &matched)
724 const char *pdata = arg;
726 if (strncmp(pdata,
"--", 2) == 0)
729 if (isalnum(*pdata, std::locale::classic()))
731 argu_desc.arg_name.push_back(*pdata);
733 while (isalnum(*pdata, std::locale::classic()) || *pdata ==
'-' || *pdata ==
'_')
735 argu_desc.arg_name.push_back(*pdata);
738 if (argu_desc.arg_name.length() > 1)
742 argu_desc.set_value =
true;
746 argu_desc.value = std::string(pdata);
750 else if (*pdata ==
'\0')
757 else if (strncmp(pdata,
"-", 1) == 0)
760 argu_desc.grouping =
true;
761 while (isalnum(*pdata, std::locale::classic()))
763 argu_desc.arg_name.push_back(*pdata);
766 matched = !argu_desc.arg_name.empty() && *pdata ==
'\0';
775const char*
const integer_pattern =
776 "(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)";
778const char*
const truthy_pattern =
781const char*
const falsy_pattern =
784const char*
const option_pattern =
785 "--([[:alnum:]][-_[:alnum:]\\.]+)(=(.*))?|-([[:alnum:]].*)";
787const char*
const option_specifier_pattern =
788 "([[:alnum:]][-_[:alnum:]\\.]*)(,[ ]*[[:alnum:]][-_[:alnum:]]*)*";
790const char*
const option_specifier_separator_pattern =
", *";
794inline IntegerDesc SplitInteger(
const std::string &text)
796 static const std::basic_regex<char> integer_matcher(integer_pattern);
799 std::regex_match(text, match, integer_matcher);
801 if (match.length() == 0)
803 throw_or_mimic<exceptions::incorrect_argument_type>(text);
807 desc.negative = match[1];
808 desc.base = match[2];
809 desc.value = match[3];
811 if (match.length(4) > 0)
813 desc.base = match[5];
821inline bool IsTrueText(
const std::string &text)
823 static const std::basic_regex<char> truthy_matcher(truthy_pattern);
825 std::regex_match(text, result, truthy_matcher);
826 return !result.empty();
829inline bool IsFalseText(
const std::string &text)
831 static const std::basic_regex<char> falsy_matcher(falsy_pattern);
833 std::regex_match(text, result, falsy_matcher);
834 return !result.empty();
840inline OptionNames split_option_names(
const std::string &text)
842 static const std::basic_regex<char> option_specifier_matcher(option_specifier_pattern);
843 if (!std::regex_match(text.c_str(), option_specifier_matcher))
845 throw_or_mimic<exceptions::invalid_option_format>(text);
848 OptionNames split_names;
850 static const std::basic_regex<char> option_specifier_separator_matcher(option_specifier_separator_pattern);
851 constexpr int use_non_matches { -1 };
852 auto token_iterator = std::sregex_token_iterator(
853 text.begin(), text.end(), option_specifier_separator_matcher, use_non_matches);
854 std::copy(token_iterator, std::sregex_token_iterator(), std::back_inserter(split_names));
858inline ArguDesc ParseArgument(
const char *arg,
bool &matched)
860 static const std::basic_regex<char> option_matcher(option_pattern);
861 std::match_results<const char*> result;
862 std::regex_match(arg, result, option_matcher);
863 matched = !result.empty();
867 argu_desc.arg_name = result[1].str();
868 argu_desc.set_value = result[2].length() > 0;
869 argu_desc.value = result[3].str();
870 if (result[4].length() > 0)
872 argu_desc.grouping =
true;
873 argu_desc.arg_name = result[4].str();
881#undef CXXOPTS_NO_REGEX
886template <
typename T,
bool B>
892 template <
typename U>
894 operator()(
bool negative, U u,
const std::string& text)
898 if (u >
static_cast<U
>((std::numeric_limits<T>::min)()))
900 throw_or_mimic<exceptions::incorrect_argument_type>(text);
905 if (u >
static_cast<U
>((std::numeric_limits<T>::max)()))
907 throw_or_mimic<exceptions::incorrect_argument_type>(text);
916 template <
typename U>
918 operator()(
bool, U,
const std::string&)
const {}
921template <
typename T,
typename U>
923check_signed_range(
bool negative, U value,
const std::string& text)
930template <
typename R,
typename T>
932checked_negate(R& r, T&& t,
const std::string&, std::true_type)
937 r =
static_cast<R
>(-
static_cast<R
>(t-1)-1);
940template <
typename R,
typename T>
942checked_negate(R&, T&&,
const std::string& text, std::false_type)
944 throw_or_mimic<exceptions::incorrect_argument_type>(text);
949integer_parser(
const std::string& text, T& value)
951 parser_tool::IntegerDesc int_desc = parser_tool::SplitInteger(text);
953 using US =
typename std::make_unsigned<T>::type;
954 constexpr bool is_signed = std::numeric_limits<T>::is_signed;
956 const bool negative = int_desc.negative.length() > 0;
957 const uint8_t base = int_desc.base.length() > 0 ? 16 : 10;
958 const std::string & value_match = int_desc.value;
962 for (
char ch : value_match)
966 if (ch >=
'0' && ch <=
'9')
968 digit =
static_cast<US
>(ch -
'0');
970 else if (base == 16 && ch >=
'a' && ch <=
'f')
972 digit =
static_cast<US
>(ch -
'a' + 10);
974 else if (base == 16 && ch >=
'A' && ch <=
'F')
976 digit =
static_cast<US
>(ch -
'A' + 10);
980 throw_or_mimic<exceptions::incorrect_argument_type>(text);
986 limit =
static_cast<US
>(std::abs(
static_cast<intmax_t
>((std::numeric_limits<T>::min)())));
990 limit = (std::numeric_limits<T>::max)();
993 if (base != 0 && result > limit / base)
995 throw_or_mimic<exceptions::incorrect_argument_type>(text);
997 if (result * base > limit - digit)
999 throw_or_mimic<exceptions::incorrect_argument_type>(text);
1002 result =
static_cast<US
>(result * base + digit);
1005 detail::check_signed_range<T>(negative, result, text);
1009 checked_negate<T>(value, result, text, std::integral_constant<bool, is_signed>());
1013 value =
static_cast<T
>(result);
1017template <
typename T>
1018void stringstream_parser(
const std::string& text, T& value)
1020 std::stringstream in(text);
1023 throw_or_mimic<exceptions::incorrect_argument_type>(text);
1027template <
typename T,
1028 typename std::enable_if<std::is_integral<T>::value>::type* =
nullptr
1030void parse_value(
const std::string& text, T& value)
1032 integer_parser(text, value);
1037parse_value(
const std::string& text,
bool& value)
1039 if (parser_tool::IsTrueText(text))
1045 if (parser_tool::IsFalseText(text))
1051 throw_or_mimic<exceptions::incorrect_argument_type>(text);
1056parse_value(
const std::string& text, std::string& value)
1064template <
typename T,
1065 typename std::enable_if<!std::is_integral<T>::value>::type* =
nullptr
1068parse_value(
const std::string& text, T& value) {
1069 stringstream_parser(text, value);
1072#ifdef CXXOPTS_HAS_OPTIONAL
1073template <
typename T>
1075parse_value(
const std::string& text, std::optional<T>& value)
1078 parse_value(text, result);
1079 value = std::move(result);
1083#ifdef CXXOPTS_HAS_FILESYSTEM
1086parse_value(
const std::string& text, std::filesystem::path& value)
1093void parse_value(
const std::string& text,
char& c)
1095 if (text.length() != 1)
1097 throw_or_mimic<exceptions::incorrect_argument_type>(text);
1103template<
typename T>
void add_value(
const std::string& text, std::vector<T>& value);
1105template <
typename T>
1107parse_value(
const std::string& text, std::vector<T>& value)
1112 std::stringstream in(text);
1114 while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
1115 add_value(token, value);
1119template <
typename T>
1121add_value(
const std::string& text, T& value)
1123 parse_value(text, value);
1126template <
typename T>
1128add_value(
const std::string& text, std::vector<T>& value)
1132 value.emplace_back(std::move(v));
1135template <
typename T>
1138 static constexpr bool value =
false;
1141template <
typename T>
1144 static constexpr bool value =
true;
1147template <
typename T>
1154 : m_result(std::make_shared<T>())
1155 , m_store(m_result.get())
1172 m_result = std::make_shared<T>();
1173 m_store = m_result.get();
1177 m_store = rhs.m_store;
1180 m_default = rhs.m_default;
1181 m_implicit = rhs.m_implicit;
1182 m_default_value = rhs.m_default_value;
1183 m_implicit_value = rhs.m_implicit_value;
1187 add(
const std::string& text)
const override
1189 add_value(text, *m_store);
1193 parse(
const std::string& text)
const override
1195 parse_value(text, *m_store);
1199 is_container()
const override
1205 parse()
const override
1207 parse_value(m_default_value, *m_store);
1211 has_default()
const override
1217 has_implicit()
const override
1222 std::shared_ptr<Value>
1223 default_value(
const std::string& value)
override
1226 m_default_value = value;
1227 return shared_from_this();
1230 std::shared_ptr<Value>
1231 implicit_value(
const std::string& value)
override
1234 m_implicit_value = value;
1235 return shared_from_this();
1238 std::shared_ptr<Value>
1239 no_implicit_value()
override
1242 return shared_from_this();
1246 get_default_value()
const override
1248 return m_default_value;
1252 get_implicit_value()
const override
1254 return m_implicit_value;
1258 is_boolean()
const override
1260 return std::is_same<T, bool>::value;
1266 if (m_store ==
nullptr)
1274 std::shared_ptr<T> m_result{};
1277 bool m_default =
false;
1278 bool m_implicit =
false;
1280 std::string m_default_value{};
1281 std::string m_implicit_value{};
1284template <
typename T>
1291 std::shared_ptr<Value>
1292 clone()
const override
1294 return std::make_shared<standard_value<T>>(*this);
1306 set_default_and_implicit();
1313 m_implicit_value =
"true";
1316 std::shared_ptr<Value>
1317 clone()
const override
1319 return std::make_shared<standard_value<bool>>(*this);
1325 set_default_and_implicit()
1328 m_default_value =
"false";
1330 m_implicit_value =
"true";
1336template <
typename T>
1337std::shared_ptr<Value>
1340 return std::make_shared<values::standard_value<T>>();
1343template <
typename T>
1344std::shared_ptr<Value>
1347 return std::make_shared<values::standard_value<T>>(&t);
1355first_or_empty(
const OptionNames& long_names)
1357 static const std::string empty{
""};
1358 return long_names.empty() ? empty : long_names.front();
1369 std::shared_ptr<const Value> val
1371 : m_short(std::move(short_))
1372 , m_long(std::move(long_))
1373 , m_desc(std::move(desc))
1374 , m_value(std::move(val))
1377 m_hash = std::hash<std::string>{}(first_long_name() + m_short);
1381 : m_desc(rhs.m_desc)
1382 , m_value(rhs.m_value->clone())
1383 , m_count(rhs.m_count)
1403 std::shared_ptr<Value>
1404 make_storage()
const
1406 return m_value->clone();
1418 first_long_name()
const
1420 return first_or_empty(m_long);
1425 essential_name()
const
1427 return m_long.empty() ? m_short : m_long.front();
1444 std::string m_short{};
1445 OptionNames m_long{};
1447 std::shared_ptr<const Value> m_value{};
1450 std::size_t m_hash{};
1459 std::string default_value;
1461 std::string implicit_value;
1462 std::string arg_help;
1470 std::string description{};
1471 std::vector<HelpOptionDetails> options{};
1480 const std::shared_ptr<const OptionDetails>& details,
1481 const std::string& text
1484 ensure_value(details);
1487 m_long_names = &details->long_names();
1493 const std::shared_ptr<const OptionDetails>& details,
1494 const std::string& text
1497 ensure_value(details);
1499 m_value->parse(text);
1500 m_long_names = &details->long_names();
1504 parse_default(
const std::shared_ptr<const OptionDetails>& details)
1506 ensure_value(details);
1508 m_long_names = &details->long_names();
1513 parse_no_value(
const std::shared_ptr<const OptionDetails>& details)
1515 m_long_names = &details->long_names();
1518#if defined(CXXOPTS_NULL_DEREF_IGNORE)
1519CXXOPTS_DIAGNOSTIC_PUSH
1520CXXOPTS_IGNORE_WARNING(
"-Wnull-dereference")
1525 count()
const noexcept
1530#if defined(CXXOPTS_NULL_DEREF_IGNORE)
1531CXXOPTS_DIAGNOSTIC_POP
1537 has_default()
const noexcept
1542 template <
typename T>
1546 if (m_value ==
nullptr) {
1547 throw_or_mimic<exceptions::option_has_no_value>(
1548 m_long_names ==
nullptr ?
"" : first_or_empty(*m_long_names));
1551 return CXXOPTS_RTTI_CAST<const values::standard_value<T>&>(*m_value).get();
1554#ifdef CXXOPTS_HAS_OPTIONAL
1555 template <
typename T>
1559 if (m_value ==
nullptr) {
1560 return std::nullopt;
1568 ensure_value(
const std::shared_ptr<const OptionDetails>& details)
1570 if (m_value ==
nullptr)
1572 m_value = details->make_storage();
1577 const OptionNames * m_long_names =
nullptr;
1580 std::shared_ptr<Value> m_value{};
1581 std::size_t m_count = 0;
1582 bool m_default =
false;
1588 KeyValue(std::string key_, std::string value_) noexcept
1589 : m_key(std::move(key_))
1590 , m_value(std::move(value_))
1608 template <
typename T>
1613 values::parse_value(m_value, result);
1619 std::string m_value;
1622using ParsedHashMap = std::unordered_map<std::size_t, OptionValue>;
1623using NameHashMap = std::unordered_map<std::string, std::size_t>;
1631 using iterator_category = std::forward_iterator_tag;
1633 using difference_type = void;
1642CXXOPTS_DIAGNOSTIC_PUSH
1643CXXOPTS_IGNORE_WARNING(
"-Weffc++")
1649 m_sequential =
false;
1650 m_iter = m_pr->m_defaults.end();
1654 m_sequential =
true;
1655 m_iter = m_pr->m_sequential.begin();
1657 if (m_iter == m_pr->m_sequential.end())
1659 m_sequential =
false;
1660 m_iter = m_pr->m_defaults.begin();
1664CXXOPTS_DIAGNOSTIC_POP
1669 if(m_sequential && m_iter == m_pr->m_sequential.end())
1671 m_sequential =
false;
1672 m_iter = m_pr->m_defaults.begin();
1685 bool operator==(
const Iterator& other)
const
1687 return (m_sequential == other.m_sequential) && (m_iter == other.m_iter);
1690 bool operator!=(
const Iterator& other)
const
1692 return !(*
this == other);
1702 return m_iter.operator->();
1707 std::vector<KeyValue>::const_iterator m_iter;
1708 bool m_sequential =
true;
1714 ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<KeyValue> sequential,
1715 std::vector<KeyValue> default_opts, std::vector<std::string>&& unmatched_args)
1716 : m_keys(std::move(keys))
1717 , m_values(std::move(values))
1718 , m_sequential(std::move(sequential))
1719 , m_defaults(std::move(default_opts))
1720 , m_unmatched(std::move(unmatched_args))
1730 return Iterator(
this);
1736 return Iterator(
this,
true);
1740 count(
const std::string& o)
const
1742 auto iter = m_keys.find(o);
1743 if (iter == m_keys.end())
1748 auto viter = m_values.find(iter->second);
1750 if (viter == m_values.end())
1755 return viter->second.count();
1759 contains(
const std::string& o)
const
1761 return static_cast<bool>(count(o));
1765 operator[](
const std::string& option)
const
1767 auto iter = m_keys.find(option);
1769 if (iter == m_keys.end())
1771 throw_or_mimic<exceptions::requested_option_not_present>(option);
1774 auto viter = m_values.find(iter->second);
1776 if (viter == m_values.end())
1778 throw_or_mimic<exceptions::requested_option_not_present>(option);
1781 return viter->second;
1784#ifdef CXXOPTS_HAS_OPTIONAL
1785 template <
typename T>
1787 as_optional(
const std::string& option)
const
1789 auto iter = m_keys.find(option);
1790 if (iter != m_keys.end())
1792 auto viter = m_values.find(iter->second);
1793 if (viter != m_values.end())
1795 return viter->second.as_optional<T>();
1798 return std::nullopt;
1802 const std::vector<KeyValue>&
1805 return m_sequential;
1808 const std::vector<std::string>&
1814 const std::vector<KeyValue>&
1821 arguments_string()
const
1824 for(
const auto& kv: m_sequential)
1826 result += kv.key() +
" = " + kv.value() +
"\n";
1828 for(
const auto& kv: m_defaults)
1830 result += kv.key() +
" = " + kv.value() +
" " +
"(default)" +
"\n";
1836 NameHashMap m_keys{};
1837 ParsedHashMap m_values{};
1838 std::vector<KeyValue> m_sequential{};
1839 std::vector<KeyValue> m_defaults{};
1840 std::vector<std::string> m_unmatched{};
1849 std::shared_ptr<const Value> value = ::cxxopts::value<bool>(),
1850 std::string arg_help =
""
1852 : opts_(std::move(opts))
1853 , desc_(std::move(desc))
1854 , value_(std::move(value))
1855 , arg_help_(std::move(arg_help))
1861 std::shared_ptr<const Value> value_;
1862 std::string arg_help_;
1865using OptionMap = std::unordered_map<std::string, std::shared_ptr<OptionDetails>>;
1866using PositionalList = std::vector<std::string>;
1867using PositionalListIterator = PositionalList::const_iterator;
1872 OptionParser(
const OptionMap& options,
const PositionalList& positional,
bool allow_unrecognised)
1873 : m_options(options)
1874 , m_positional(positional)
1875 , m_allow_unrecognised(allow_unrecognised)
1880 parse(
int argc,
const char*
const* argv);
1883 consume_positional(
const std::string& a, PositionalListIterator& next);
1889 const char*
const* argv,
1891 const std::shared_ptr<OptionDetails>& value,
1892 const std::string& name
1896 add_to_option(
const std::shared_ptr<OptionDetails>& value,
const std::string& arg);
1901 const std::shared_ptr<OptionDetails>& value,
1902 const std::string& name,
1903 const std::string& arg =
""
1907 parse_default(
const std::shared_ptr<OptionDetails>& details);
1910 parse_no_value(
const std::shared_ptr<OptionDetails>& details);
1914 void finalise_aliases();
1916 const OptionMap& m_options;
1917 const PositionalList& m_positional;
1919 std::vector<KeyValue> m_sequential{};
1920 std::vector<KeyValue> m_defaults{};
1921 bool m_allow_unrecognised;
1923 ParsedHashMap m_parsed{};
1924 NameHashMap m_keys{};
1931 explicit Options(std::string program_name, std::string help_string =
"")
1932 : m_program(std::move(program_name))
1933 , m_help_string(toLocalString(std::move(help_string)))
1934 , m_custom_help(
"[OPTION...]")
1935 , m_positional_help(
"positional parameters")
1936 , m_show_positional(
false)
1937 , m_allow_unrecognised(
false)
1939 , m_tab_expansion(
false)
1940 , m_options(std::make_shared<OptionMap>())
1945 positional_help(std::string help_text)
1947 m_positional_help = std::move(help_text);
1952 custom_help(std::string help_text)
1954 m_custom_help = std::move(help_text);
1959 show_positional_help()
1961 m_show_positional =
true;
1966 allow_unrecognised_options()
1968 m_allow_unrecognised =
true;
1973 set_width(std::size_t width)
1980 set_tab_expansion(
bool expansion=
true)
1982 m_tab_expansion = expansion;
1987 parse(
int argc,
const char*
const* argv);
1990 add_options(std::string group =
"");
1995 const std::string& group,
1996 std::initializer_list<Option> options
2002 const std::string& group,
2009 const std::string& group,
2010 const std::string& s,
2011 const OptionNames& l,
2013 const std::shared_ptr<const Value>& value,
2014 std::string arg_help
2020 const std::string& group,
2021 const std::string& short_name,
2022 const std::string& single_long_name,
2024 const std::shared_ptr<const Value>& value,
2025 std::string arg_help
2028 OptionNames long_names;
2029 long_names.emplace_back(single_long_name);
2030 add_option(group, short_name, long_names, desc, value, arg_help);
2035 parse_positional(std::string option);
2038 parse_positional(std::vector<std::string> options);
2041 parse_positional(std::initializer_list<std::string> options);
2043 template <
typename Iterator>
2045 parse_positional(Iterator begin, Iterator end) {
2046 parse_positional(std::vector<std::string>{begin, end});
2050 help(
const std::vector<std::string>& groups = {},
bool print_usage=
true)
const;
2052 std::vector<std::string>
2056 group_help(
const std::string& group)
const;
2058 const std::string& program()
const
2068 const std::string& option,
2069 const std::shared_ptr<OptionDetails>& details
2073 help_one_group(
const std::string& group)
const;
2079 const std::vector<std::string>& groups
2083 generate_all_groups_help(String& result)
const;
2085 std::string m_program{};
2086 String m_help_string{};
2087 std::string m_custom_help{};
2088 std::string m_positional_help{};
2089 bool m_show_positional;
2090 bool m_allow_unrecognised;
2091 std::size_t m_width;
2092 bool m_tab_expansion;
2094 std::shared_ptr<OptionMap> m_options;
2095 std::vector<std::string> m_positional{};
2096 std::unordered_set<std::string> m_positional_set{};
2099 std::vector<std::string> m_group{};
2100 std::map<std::string, HelpGroupDetails> m_help{};
2108 : m_options(options), m_group(std::move(group))
2115 const std::string& opts,
2116 const std::string& desc,
2117 const std::shared_ptr<const Value>& value
2118 = ::cxxopts::value<bool>(),
2119 std::string arg_help =
""
2124 std::string m_group;
2128constexpr std::size_t OPTION_LONGEST = 30;
2129constexpr std::size_t OPTION_DESC_GAP = 2;
2137 const auto& s = o.s;
2138 const auto& l = first_or_empty(o.l);
2140 String result =
" ";
2144 result +=
"-" + toLocalString(s);
2157 result +=
" --" + toLocalString(l);
2160 auto arg = !o.arg_help.empty() ? toLocalString(o.arg_help) :
"arg";
2166 result +=
" [=" + arg +
"(=" + toLocalString(o.implicit_value) +
")]";
2170 result +=
" " + arg;
2180 const HelpOptionDetails& o,
2182 std::size_t allowed,
2188 if (o.has_default && (!o.is_boolean || o.default_value !=
"false"))
2190 if(!o.default_value.empty())
2192 desc += toLocalString(
" (default: " + o.default_value +
")");
2196 desc += toLocalString(
" (default: \"\")");
2205 auto size = std::size_t{ 0 };
2206 for (
auto c = std::begin(desc); c != std::end(desc); ++c)
2213 else if (*c ==
'\t')
2215 auto skip = 8 - size % 8;
2216 stringAppend(desc2, skip,
' ');
2230 auto current = std::begin(desc);
2231 auto previous = current;
2232 auto startLine = current;
2233 auto lastSpace = current;
2235 auto size = std::size_t{};
2238 bool onlyWhiteSpace =
true;
2240 while (current != std::end(desc))
2242 appendNewLine =
false;
2243 if (*previous ==
' ' || *previous ==
'\t')
2245 lastSpace = current;
2247 if (*current !=
' ' && *current !=
'\t')
2249 onlyWhiteSpace =
false;
2252 while (*current ==
'\n')
2256 appendNewLine =
true;
2259 if (!appendNewLine && size >= allowed)
2261 if (lastSpace != startLine)
2263 current = lastSpace;
2266 appendNewLine =
true;
2271 stringAppend(result, startLine, current);
2272 startLine = current;
2273 lastSpace = current;
2275 if (*previous !=
'\n')
2277 stringAppend(result,
"\n");
2280 stringAppend(result, start,
' ');
2282 if (*previous !=
'\n')
2284 stringAppend(result, lastSpace, current);
2287 onlyWhiteSpace =
true;
2297 if (!onlyWhiteSpace)
2299 stringAppend(result, startLine, previous);
2311 const std::string &group,
2312 std::initializer_list<Option> options
2315 OptionAdder option_adder(*
this, group);
2316 for (
const auto &option: options)
2318 option_adder(option.opts_, option.desc_, option.value_, option.arg_help_);
2324Options::add_options(std::string group)
2326 return OptionAdder(*
this, std::move(group));
2331OptionAdder::operator()
2333 const std::string& opts,
2334 const std::string& desc,
2335 const std::shared_ptr<const Value>& value,
2336 std::string arg_help
2339 OptionNames option_names = values::parser_tool::split_option_names(opts);
2342 std::string short_name {
""};
2343 auto first_short_name_iter =
2344 std::partition(option_names.begin(), option_names.end(),
2345 [&](
const std::string& name) { return name.length() > 1; }
2347 auto num_length_1_names = (option_names.end() - first_short_name_iter);
2348 switch(num_length_1_names) {
2350 short_name = *first_short_name_iter;
2351 option_names.erase(first_short_name_iter);
2352 CXXOPTS_FALLTHROUGH;
2356 throw_or_mimic<exceptions::invalid_option_format>(opts);
2359 m_options.add_option
2374OptionParser::parse_default(
const std::shared_ptr<OptionDetails>& details)
2377 auto& store = m_parsed[details->hash()];
2378 store.parse_default(details);
2379 m_defaults.emplace_back(details->essential_name(), details->value().get_default_value());
2384OptionParser::parse_no_value(
const std::shared_ptr<OptionDetails>& details)
2386 auto& store = m_parsed[details->hash()];
2387 store.parse_no_value(details);
2392OptionParser::parse_option
2394 const std::shared_ptr<OptionDetails>& value,
2395 const std::string& ,
2396 const std::string& arg
2399 auto hash = value->hash();
2400 auto& result = m_parsed[hash];
2401 result.parse(value, arg);
2403 m_sequential.emplace_back(value->essential_name(), arg);
2408OptionParser::checked_parse_arg
2411 const char*
const* argv,
2413 const std::shared_ptr<OptionDetails>& value,
2414 const std::string& name
2417 if (current + 1 >= argc)
2419 if (value->value().has_implicit())
2421 parse_option(value, name, value->value().get_implicit_value());
2425 throw_or_mimic<exceptions::missing_argument>(name);
2430 if (value->value().has_implicit())
2432 parse_option(value, name, value->value().get_implicit_value());
2436 parse_option(value, name, argv[current + 1]);
2444OptionParser::add_to_option(
const std::shared_ptr<OptionDetails>& value,
const std::string& arg)
2446 auto hash = value->hash();
2447 auto& result = m_parsed[hash];
2448 result.add(value, arg);
2450 m_sequential.emplace_back(value->essential_name(), arg);
2455OptionParser::consume_positional(
const std::string& a, PositionalListIterator& next)
2457 while (next != m_positional.end())
2459 auto iter = m_options.find(*next);
2460 if (iter != m_options.end())
2462 if (!iter->second->value().is_container())
2464 auto& result = m_parsed[iter->second->hash()];
2465 if (result.count() == 0)
2467 add_to_option(iter->second, a);
2474 add_to_option(iter->second, a);
2477 throw_or_mimic<exceptions::no_such_option>(*next);
2485Options::parse_positional(std::string option)
2487 parse_positional(std::vector<std::string>{std::move(option)});
2492Options::parse_positional(std::vector<std::string> options)
2494 m_positional = std::move(options);
2496 m_positional_set.insert(m_positional.begin(), m_positional.end());
2501Options::parse_positional(std::initializer_list<std::string> options)
2503 parse_positional(std::vector<std::string>(options));
2508Options::parse(
int argc,
const char*
const* argv)
2510 OptionParser parser(*m_options, m_positional, m_allow_unrecognised);
2512 return parser.parse(argc, argv);
2516OptionParser::parse(
int argc,
const char*
const* argv)
2519 bool consume_remaining =
false;
2520 auto next_positional = m_positional.begin();
2522 std::vector<std::string> unmatched;
2524 while (current != argc)
2526 if (strcmp(argv[current],
"--") == 0)
2528 consume_remaining =
true;
2532 bool matched =
false;
2533 values::parser_tool::ArguDesc argu_desc =
2534 values::parser_tool::ParseArgument(argv[current], matched);
2541 if (argv[current][0] ==
'-' && argv[current][1] !=
'\0') {
2542 if (!m_allow_unrecognised) {
2543 throw_or_mimic<exceptions::invalid_option_syntax>(argv[current]);
2549 if (consume_positional(argv[current], next_positional))
2554 unmatched.emplace_back(argv[current]);
2561 if (argu_desc.grouping)
2563 const std::string& s = argu_desc.arg_name;
2565 for (std::size_t i = 0; i != s.size(); ++i)
2567 std::string name(1, s[i]);
2568 auto iter = m_options.find(name);
2570 if (iter == m_options.end())
2572 if (m_allow_unrecognised)
2574 unmatched.push_back(std::string(
"-") + s[i]);
2578 throw_or_mimic<exceptions::no_such_option>(name);
2581 auto value = iter->second;
2583 if (i + 1 == s.size())
2586 checked_parse_arg(argc, argv, current, value, name);
2588 else if (value->value().has_implicit())
2590 parse_option(value, name, value->value().get_implicit_value());
2592 else if (i + 1 < s.size())
2594 std::string arg_value = s.substr(i + 1);
2595 parse_option(value, name, arg_value);
2601 throw_or_mimic<exceptions::option_requires_argument>(name);
2605 else if (argu_desc.arg_name.length() != 0)
2607 const std::string& name = argu_desc.arg_name;
2609 auto iter = m_options.find(name);
2611 if (iter == m_options.end())
2613 if (m_allow_unrecognised)
2616 unmatched.emplace_back(argv[current]);
2621 throw_or_mimic<exceptions::no_such_option>(name);
2624 auto opt = iter->second;
2627 if (argu_desc.set_value)
2631 parse_option(opt, name, argu_desc.value);
2636 checked_parse_arg(argc, argv, current, opt, name);
2645 for (
auto& opt : m_options)
2647 auto& detail = opt.second;
2648 const auto& value = detail->value();
2650 auto& store = m_parsed[detail->hash()];
2652 if (value.has_default()) {
2653 if (!store.count() && !store.has_default()) {
2654 parse_default(detail);
2658 parse_no_value(detail);
2662 if (consume_remaining)
2664 while (current < argc)
2666 if (!consume_positional(argv[current], next_positional)) {
2673 while (current != argc) {
2674 unmatched.emplace_back(argv[current]);
2681 ParseResult parsed(std::move(m_keys), std::move(m_parsed), std::move(m_sequential), std::move(m_defaults), std::move(unmatched));
2687OptionParser::finalise_aliases()
2689 for (
auto& option: m_options)
2691 auto& detail = *option.second;
2692 auto hash = detail.hash();
2693 m_keys[detail.short_name()] = hash;
2694 for(
const auto& long_name : detail.long_names()) {
2695 m_keys[long_name] = hash;
2698 m_parsed.emplace(hash, OptionValue());
2706 const std::string& group,
2707 const Option& option
2710 add_options(group, {option});
2717 const std::string& group,
2718 const std::string& s,
2719 const OptionNames& l,
2721 const std::shared_ptr<const Value>& value,
2722 std::string arg_help
2725 auto stringDesc = toLocalString(std::move(desc));
2726 auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);
2730 add_one_option(s, option);
2733 for(
const auto& long_name : l) {
2734 add_one_option(long_name, option);
2739 if (m_help.find(group) == m_help.end())
2741 m_group.push_back(group);
2744 auto& options = m_help[group];
2746 options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
2747 value->has_default(), value->get_default_value(),
2748 value->has_implicit(), value->get_implicit_value(),
2749 std::move(arg_help),
2750 value->is_container(),
2751 value->is_boolean()});
2756Options::add_one_option
2758 const std::string& option,
2759 const std::shared_ptr<OptionDetails>& details
2762 auto in = m_options->emplace(option, details);
2766 throw_or_mimic<exceptions::option_already_exists>(option);
2772Options::help_one_group(
const std::string& g)
const
2774 using OptionHelp = std::vector<std::pair<String, String>>;
2776 auto group = m_help.find(g);
2777 if (group == m_help.end())
2784 std::size_t longest = 0;
2790 result += toLocalString(
" " + g +
" options:\n");
2793 for (
const auto& o : group->second.options)
2796 m_positional_set.find(o.l.front()) != m_positional_set.end() &&
2802 auto s = format_option(o);
2803 longest = (std::max)(longest, stringLength(s));
2804 format.push_back(std::make_pair(s, String()));
2806 longest = (std::min)(longest, OPTION_LONGEST);
2809 std::size_t allowed = 10;
2810 if (m_width > allowed + longest + OPTION_DESC_GAP)
2812 allowed = m_width - longest - OPTION_DESC_GAP;
2815 auto fiter = format.begin();
2816 for (
const auto& o : group->second.options)
2819 m_positional_set.find(o.l.front()) != m_positional_set.end() &&
2825 auto d = format_description(o, longest + OPTION_DESC_GAP, allowed, m_tab_expansion);
2827 result += fiter->first;
2828 if (stringLength(fiter->first) > longest)
2831 result += toLocalString(std::string(longest + OPTION_DESC_GAP,
' '));
2835 result += toLocalString(std::string(longest + OPTION_DESC_GAP -
2836 stringLength(fiter->first),
2850Options::generate_group_help
2853 const std::vector<std::string>& print_groups
2856 for (std::size_t i = 0; i != print_groups.size(); ++i)
2858 const String& group_help_text = help_one_group(print_groups[i]);
2859 if (empty(group_help_text))
2863 result += group_help_text;
2864 if (i < print_groups.size() - 1)
2873Options::generate_all_groups_help(String& result)
const
2875 generate_group_help(result, m_group);
2880Options::help(
const std::vector<std::string>& help_groups,
bool print_usage)
const
2882 String result = m_help_string;
2885 result+=
"\nUsage:\n " + toLocalString(m_program);
2888 if (!m_custom_help.empty())
2890 result +=
" " + toLocalString(m_custom_help);
2893 if (!m_positional.empty() && !m_positional_help.empty()) {
2894 result +=
" " + toLocalString(m_positional_help);
2899 if (help_groups.empty())
2901 generate_all_groups_help(result);
2905 generate_group_help(result, help_groups);
2908 return toUTF8String(result);
2912std::vector<std::string>
2913Options::groups()
const
2919const HelpGroupDetails&
2920Options::group_help(
const std::string& group)
const
2922 return m_help.at(group);
Definition cxxopts.hpp:1586
Definition cxxopts.hpp:2104
Definition cxxopts.hpp:1362
Definition cxxopts.hpp:1870
Definition cxxopts.hpp:1475
Definition cxxopts.hpp:1928
Definition cxxopts.hpp:1629
Definition cxxopts.hpp:1626
Definition cxxopts.hpp:370
Definition cxxopts.hpp:421
Definition cxxopts.hpp:517
Definition cxxopts.hpp:555
Definition cxxopts.hpp:476
Definition cxxopts.hpp:495
Definition cxxopts.hpp:486
Definition cxxopts.hpp:459
Definition cxxopts.hpp:543
Definition cxxopts.hpp:506
Definition cxxopts.hpp:450
Definition cxxopts.hpp:534
Definition cxxopts.hpp:440
Definition cxxopts.hpp:1149
Definition cxxopts.hpp:1286
Definition cxxopts.hpp:1468
Definition cxxopts.hpp:1454
Definition cxxopts.hpp:1844
Definition cxxopts.hpp:887
Definition cxxopts.hpp:1137