aboutsummaryrefslogtreecommitdiff
path: root/src/opts
diff options
context:
space:
mode:
authorDenis Evsyukov <[email protected]>2020-02-22 10:10:25 +0300
committerDenis Evsyukov <[email protected]>2020-02-22 10:10:25 +0300
commit2180154b127b1f171bef690377c312eb11a6357a (patch)
treee47969103050963136a3bc11a82a8cec8cd12a2f /src/opts
parentChange sha256 to sha1, and move parsing to main module (diff)
downloadt-2180154b127b1f171bef690377c312eb11a6357a.tar.xz
t-2180154b127b1f171bef690377c312eb11a6357a.zip
[~] update cxxopts
Diffstat (limited to 'src/opts')
-rw-r--r--src/opts/cxxopts.hpp3209
1 files changed, 1533 insertions, 1676 deletions
diff --git a/src/opts/cxxopts.hpp b/src/opts/cxxopts.hpp
index 236ecbe..99e0aab 100644
--- a/src/opts/cxxopts.hpp
+++ b/src/opts/cxxopts.hpp
@@ -54,16 +54,16 @@ THE SOFTWARE.
namespace cxxopts
{
- static constexpr struct {
- uint8_t major, minor, patch;
- } version = {
- CXXOPTS__VERSION_MAJOR,
- CXXOPTS__VERSION_MINOR,
- CXXOPTS__VERSION_PATCH
- };
-}
-
-//when we ask opts to use Unicode, help strings are processed using ICU,
+static constexpr struct
+{
+ uint8_t major, minor, patch;
+} version = {
+ CXXOPTS__VERSION_MAJOR,
+ CXXOPTS__VERSION_MINOR,
+ CXXOPTS__VERSION_PATCH};
+} // namespace cxxopts
+
+//when we ask cxxopts to use Unicode, help strings are processed using ICU,
//which results in the correct lengths being computed for strings when they
//are formatted for the help output
//it is necessary to make sure that <unicode/unistr.h> can be found by the
@@ -72,1855 +72,1688 @@ namespace cxxopts
#ifdef CXXOPTS_USE_UNICODE
#include <unicode/unistr.h>
-namespace opts
+namespace cxxopts
{
- typedef icu::UnicodeString String;
+typedef icu::UnicodeString String;
- inline
- String
- toLocalString(std::string s)
- {
+inline String
+toLocalString(std::string s)
+{
return icu::UnicodeString::fromUTF8(std::move(s));
- }
-
- class UnicodeStringIterator : public
- std::iterator<std::forward_iterator_tag, int32_t>
- {
- public:
+}
- UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
- : s(string)
- , i(pos)
+class UnicodeStringIterator : public std::iterator<std::forward_iterator_tag, int32_t>
+{
+public:
+ UnicodeStringIterator(const icu::UnicodeString *string, int32_t pos)
+ : s(string), i(pos)
{
}
value_type
operator*() const
{
- return s->char32At(i);
+ return s->char32At(i);
}
bool
- operator==(const UnicodeStringIterator& rhs) const
+ operator==(const UnicodeStringIterator &rhs) const
{
- return s == rhs.s && i == rhs.i;
+ return s == rhs.s && i == rhs.i;
}
bool
- operator!=(const UnicodeStringIterator& rhs) const
+ operator!=(const UnicodeStringIterator &rhs) const
{
- return !(*this == rhs);
+ return !(*this == rhs);
}
- UnicodeStringIterator&
+ UnicodeStringIterator &
operator++()
{
- ++i;
- return *this;
+ ++i;
+ return *this;
}
UnicodeStringIterator
operator+(int32_t v)
{
- return UnicodeStringIterator(s, i + v);
+ return UnicodeStringIterator(s, i + v);
}
- private:
- const icu::UnicodeString* s;
+private:
+ const icu::UnicodeString *s;
int32_t i;
- };
+};
- inline
- String&
- stringAppend(String&s, String a)
- {
+inline String &
+stringAppend(String &s, String a)
+{
return s.append(std::move(a));
- }
+}
- inline
- String&
- stringAppend(String& s, int n, UChar32 c)
- {
+inline String &
+stringAppend(String &s, int n, UChar32 c)
+{
for (int i = 0; i != n; ++i)
{
- s.append(c);
+ s.append(c);
}
return s;
- }
+}
- template <typename Iterator>
- String&
- stringAppend(String& s, Iterator begin, Iterator end)
- {
+template <typename Iterator>
+String &
+stringAppend(String &s, Iterator begin, Iterator end)
+{
while (begin != end)
{
- s.append(*begin);
- ++begin;
+ s.append(*begin);
+ ++begin;
}
return s;
- }
+}
- inline
- size_t
- stringLength(const String& s)
- {
+inline size_t
+stringLength(const String &s)
+{
return s.length();
- }
+}
- inline
- std::string
- toUTF8String(const String& s)
- {
+inline std::string
+toUTF8String(const String &s)
+{
std::string result;
s.toUTF8String(result);
return result;
- }
+}
- inline
- bool
- empty(const String& s)
- {
+inline bool
+empty(const String &s)
+{
return s.isEmpty();
- }
}
+} // namespace cxxopts
namespace std
{
- inline
- opts::UnicodeStringIterator
- begin(const icu::UnicodeString& s)
- {
- return opts::UnicodeStringIterator(&s, 0);
- }
-
- inline
- opts::UnicodeStringIterator
- end(const icu::UnicodeString& s)
- {
- return opts::UnicodeStringIterator(&s, s.length());
- }
+inline cxxopts::UnicodeStringIterator
+begin(const icu::UnicodeString &s)
+{
+ return cxxopts::UnicodeStringIterator(&s, 0);
}
+inline cxxopts::UnicodeStringIterator
+end(const icu::UnicodeString &s)
+{
+ return cxxopts::UnicodeStringIterator(&s, s.length());
+}
+} // namespace std
+
//ifdef CXXOPTS_USE_UNICODE
#else
namespace cxxopts
{
- typedef std::string String;
+typedef std::string String;
- template <typename T>
- T
- toLocalString(T&& t)
- {
- return std::forward<T>(t);
- }
+template <typename T>
+T toLocalString(T &&t)
+{
+ return std::forward<T>(t);
+}
- inline
- size_t
- stringLength(const String& s)
- {
- return s.length();
- }
+inline size_t
+stringLength(const String &s)
+{
+ return s.length();
+}
- inline
- String&
- stringAppend(String&s, String a)
- {
- return s.append(std::move(a));
- }
+inline String &
+stringAppend(String &s, String a)
+{
+ return s.append(std::move(a));
+}
- inline
- String&
- stringAppend(String& s, size_t n, char c)
- {
- return s.append(n, c);
- }
+inline String &
+stringAppend(String &s, size_t n, char c)
+{
+ return s.append(n, c);
+}
- template <typename Iterator>
- String&
- stringAppend(String& s, Iterator begin, Iterator end)
- {
- return s.append(begin, end);
- }
+template <typename Iterator>
+String &
+stringAppend(String &s, Iterator begin, Iterator end)
+{
+ return s.append(begin, end);
+}
- template <typename T>
- std::string
- toUTF8String(T&& t)
- {
- return std::forward<T>(t);
- }
+template <typename T>
+std::string
+toUTF8String(T &&t)
+{
+ return std::forward<T>(t);
+}
- inline
- bool
- empty(const std::string& s)
- {
- return s.empty();
- }
+inline bool
+empty(const std::string &s)
+{
+ return s.empty();
}
+} // namespace cxxopts
//ifdef CXXOPTS_USE_UNICODE
#endif
namespace cxxopts
{
- namespace
- {
+namespace
+{
#ifdef _WIN32
- const std::string LQUOTE("\'");
- const std::string RQUOTE("\'");
+const std::string LQUOTE("\'");
+const std::string RQUOTE("\'");
#else
- const std::string LQUOTE("‘");
- const std::string RQUOTE("’");
+const std::string LQUOTE("‘");
+const std::string RQUOTE("’");
#endif
- }
-
- class Value : public std::enable_shared_from_this<Value>
- {
- public:
+} // namespace
- virtual ~Value() = default;
+class Value : public std::enable_shared_from_this<Value>
+{
+public:
+ virtual ~Value() = default;
- virtual
- std::shared_ptr<Value>
- clone() const = 0;
+ virtual std::shared_ptr<Value>
+ clone() const = 0;
- virtual void
- parse(const std::string& text) const = 0;
+ virtual void
+ parse(const std::string &text) const = 0;
- virtual void
- parse() const = 0;
+ virtual void
+ parse() const = 0;
- virtual bool
- has_default() const = 0;
+ virtual bool
+ has_default() const = 0;
- virtual bool
- is_container() const = 0;
+ virtual bool
+ is_container() const = 0;
- virtual bool
- has_implicit() const = 0;
+ virtual bool
+ has_implicit() const = 0;
- virtual std::string
- get_default_value() const = 0;
+ virtual std::string
+ get_default_value() const = 0;
- virtual std::string
- get_implicit_value() const = 0;
+ virtual std::string
+ get_implicit_value() const = 0;
- virtual std::shared_ptr<Value>
- default_value(const std::string& value) = 0;
+ virtual std::shared_ptr<Value>
+ default_value(const std::string &value) = 0;
- virtual std::shared_ptr<Value>
- implicit_value(const std::string& value) = 0;
+ virtual std::shared_ptr<Value>
+ implicit_value(const std::string &value) = 0;
- virtual std::shared_ptr<Value>
- no_implicit_value() = 0;
+ virtual std::shared_ptr<Value>
+ no_implicit_value() = 0;
- virtual bool
- is_boolean() const = 0;
- };
+ virtual bool
+ is_boolean() const = 0;
+};
- class OptionException : public std::exception
+class OptionException : public std::exception
+{
+public:
+ OptionException(const std::string &message)
+ : m_message(message)
{
- public:
- OptionException(const std::string& message)
- : m_message(message)
- {
- }
+ }
- virtual const char*
- what() const noexcept
- {
- return m_message.c_str();
- }
+ virtual const char *
+ what() const noexcept
+ {
+ return m_message.c_str();
+ }
- private:
- std::string m_message;
- };
+private:
+ std::string m_message;
+};
- class OptionSpecException : public OptionException
+class OptionSpecException : public OptionException
+{
+public:
+ OptionSpecException(const std::string &message)
+ : OptionException(message)
{
- public:
+ }
+};
- OptionSpecException(const std::string& message)
- : OptionException(message)
- {
- }
- };
+class OptionParseException : public OptionException
+{
+public:
+ OptionParseException(const std::string &message)
+ : OptionException(message)
+ {
+ }
+};
- class OptionParseException : public OptionException
+class option_exists_error : public OptionSpecException
+{
+public:
+ option_exists_error(const std::string &option)
+ : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists")
{
- public:
- OptionParseException(const std::string& message)
- : OptionException(message)
- {
- }
- };
+ }
+};
- class option_exists_error : public OptionSpecException
+class invalid_option_format_error : public OptionSpecException
+{
+public:
+ invalid_option_format_error(const std::string &format)
+ : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE)
{
- public:
- option_exists_error(const std::string& option)
- : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists")
- {
- }
- };
+ }
+};
- class invalid_option_format_error : public OptionSpecException
+class option_syntax_exception : public OptionParseException
+{
+public:
+ option_syntax_exception(const std::string &text)
+ : OptionParseException("Argument " + LQUOTE + text + RQUOTE +
+ " starts with a - but has incorrect syntax")
{
- public:
- invalid_option_format_error(const std::string& format)
- : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE)
- {
- }
- };
+ }
+};
- class option_syntax_exception : public OptionParseException {
- public:
- option_syntax_exception(const std::string& text)
- : OptionParseException("Argument " + LQUOTE + text + RQUOTE +
- " starts with a - but has incorrect syntax")
- {
- }
- };
+class option_not_exists_exception : public OptionParseException
+{
+public:
+ option_not_exists_exception(const std::string &option)
+ : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist")
+ {
+ }
+};
- class option_not_exists_exception : public OptionParseException
+class missing_argument_exception : public OptionParseException
+{
+public:
+ missing_argument_exception(const std::string &option)
+ : OptionParseException(
+ "Option " + LQUOTE + option + RQUOTE + " is missing an argument")
{
- public:
- option_not_exists_exception(const std::string& option)
- : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist")
- {
- }
- };
+ }
+};
- class missing_argument_exception : public OptionParseException
+class option_requires_argument_exception : public OptionParseException
+{
+public:
+ option_requires_argument_exception(const std::string &option)
+ : OptionParseException(
+ "Option " + LQUOTE + option + RQUOTE + " requires an argument")
{
- public:
- missing_argument_exception(const std::string& option)
- : OptionParseException(
- "Option " + LQUOTE + option + RQUOTE + " is missing an argument"
- )
- {
- }
- };
+ }
+};
- class option_requires_argument_exception : public OptionParseException
+class option_not_has_argument_exception : public OptionParseException
+{
+public:
+ option_not_has_argument_exception(
+ const std::string &option,
+ const std::string &arg)
+ : OptionParseException(
+ "Option " + LQUOTE + option + RQUOTE +
+ " does not take an argument, but argument " +
+ LQUOTE + arg + RQUOTE + " given")
{
- public:
- option_requires_argument_exception(const std::string& option)
- : OptionParseException(
- "Option " + LQUOTE + option + RQUOTE + " requires an argument"
- )
- {
- }
- };
-
- class option_not_has_argument_exception : public OptionParseException
- {
- public:
- option_not_has_argument_exception
- (
- const std::string& option,
- const std::string& arg
- )
- : OptionParseException(
- "Option " + LQUOTE + option + RQUOTE +
- " does not take an argument, but argument " +
- LQUOTE + arg + RQUOTE + " given"
- )
- {
- }
- };
+ }
+};
- class option_not_present_exception : public OptionParseException
+class option_not_present_exception : public OptionParseException
+{
+public:
+ option_not_present_exception(const std::string &option)
+ : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present")
{
- public:
- option_not_present_exception(const std::string& option)
- : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present")
- {
- }
- };
-
- class argument_incorrect_type : public OptionParseException
- {
- public:
- argument_incorrect_type
- (
- const std::string& arg
- )
- : OptionParseException(
- "Argument " + LQUOTE + arg + RQUOTE + " failed to parse"
- )
- {
- }
- };
+ }
+};
- class option_required_exception : public OptionParseException
+class argument_incorrect_type : public OptionParseException
+{
+public:
+ argument_incorrect_type(
+ const std::string &arg)
+ : OptionParseException(
+ "Argument " + LQUOTE + arg + RQUOTE + " failed to parse")
{
- public:
- option_required_exception(const std::string& option)
- : OptionParseException(
- "Option " + LQUOTE + option + RQUOTE + " is required but not present"
- )
- {
- }
- };
+ }
+};
- template <typename T>
- void throw_or_mimic(const std::string& text)
+class option_required_exception : public OptionParseException
+{
+public:
+ option_required_exception(const std::string &option)
+ : OptionParseException(
+ "Option " + LQUOTE + option + RQUOTE + " is required but not present")
{
- static_assert(std::is_base_of<std::exception, T>::value,
- "throw_or_mimic only works on std::exception and "
- "deriving classes");
+ }
+};
+
+template <typename T>
+void throw_or_mimic(const std::string &text)
+{
+ static_assert(std::is_base_of<std::exception, T>::value,
+ "throw_or_mimic only works on std::exception and "
+ "deriving classes");
#ifndef CXXOPTS_NO_EXCEPTIONS
- // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw
- throw T{text};
+ // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw
+ throw T{text};
#else
- // Otherwise manually instantiate the exception, print what() to stderr,
+ // Otherwise manually instantiate the exception, print what() to stderr,
// and abort
T exception{text};
std::cerr << exception.what() << std::endl;
std::cerr << "Aborting (exceptions disabled)..." << std::endl;
std::abort();
#endif
- }
-
- namespace values
- {
- namespace
- {
- std::basic_regex<char> integer_pattern
- ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
- std::basic_regex<char> truthy_pattern
- ("(t|T)(rue)?|1");
- std::basic_regex<char> falsy_pattern
- ("(f|F)(alse)?|0");
- }
+}
- namespace detail
- {
- template <typename T, bool B>
- struct SignedCheck;
+namespace values
+{
+namespace
+{
+std::basic_regex<char> integer_pattern("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
+std::basic_regex<char> truthy_pattern("(t|T)(rue)?|1");
+std::basic_regex<char> falsy_pattern("(f|F)(alse)?|0");
+} // namespace
- template <typename T>
- struct SignedCheck<T, true>
- {
- template <typename U>
- void
- operator()(bool negative, U u, const std::string& text)
- {
- if (negative)
- {
- if (u > static_cast<U>((std::numeric_limits<T>::min)()))
- {
- throw_or_mimic<argument_incorrect_type>(text);
- }
- }
- else
- {
- if (u > static_cast<U>((std::numeric_limits<T>::max)()))
- {
- throw_or_mimic<argument_incorrect_type>(text);
- }
- }
- }
- };
+namespace detail
+{
+template <typename T, bool B>
+struct SignedCheck;
- template <typename T>
- struct SignedCheck<T, false>
- {
- template <typename U>
- void
- operator()(bool, U, const std::string&) {}
- };
-
- template <typename T, typename U>
- void
- check_signed_range(bool negative, U value, const std::string& text)
+template <typename T>
+struct SignedCheck<T, true>
+{
+ template <typename U>
+ void
+ operator()(bool negative, U u, const std::string &text)
+ {
+ if (negative)
+ {
+ if (u > static_cast<U>((std::numeric_limits<T>::min)()))
{
- SignedCheck<T, std::numeric_limits<T>::is_signed>()(negative, value, text);
+ throw_or_mimic<argument_incorrect_type>(text);
}
}
-
- template <typename R, typename T>
- R
- checked_negate(T&& t, const std::string&, std::true_type)
- {
- // if we got to here, then `t` is a positive number that fits into
- // `R`. So to avoid MSVC C4146, we first cast it to `R`.
- // See https://github.com/jarro2783/cxxopts/issues/62 for more details.
- return static_cast<R>(-static_cast<R>(t-1)-1);
- }
-
- template <typename R, typename T>
- T
- checked_negate(T&& t, const std::string& text, std::false_type)
- {
- throw_or_mimic<argument_incorrect_type>(text);
- return t;
- }
-
- template <typename T>
- void
- integer_parser(const std::string& text, T& value)
+ else
{
- std::smatch match;
- std::regex_match(text, match, integer_pattern);
-
- if (match.length() == 0)
+ if (u > static_cast<U>((std::numeric_limits<T>::max)()))
{
throw_or_mimic<argument_incorrect_type>(text);
}
+ }
+ }
+};
- if (match.length(4) > 0)
- {
- value = 0;
- return;
- }
-
- using US = typename std::make_unsigned<T>::type;
-
- constexpr bool is_signed = std::numeric_limits<T>::is_signed;
- const bool negative = match.length(1) > 0;
- const uint8_t base = match.length(2) > 0 ? 16 : 10;
-
- auto value_match = match[3];
-
- US result = 0;
-
- for (auto iter = value_match.first; iter != value_match.second; ++iter)
- {
- US digit = 0;
+template <typename T>
+struct SignedCheck<T, false>
+{
+ template <typename U>
+ void
+ operator()(bool, U, const std::string &) {}
+};
- if (*iter >= '0' && *iter <= '9')
- {
- digit = static_cast<US>(*iter - '0');
- }
- else if (base == 16 && *iter >= 'a' && *iter <= 'f')
- {
- digit = static_cast<US>(*iter - 'a' + 10);
- }
- else if (base == 16 && *iter >= 'A' && *iter <= 'F')
- {
- digit = static_cast<US>(*iter - 'A' + 10);
- }
- else
- {
- throw_or_mimic<argument_incorrect_type>(text);
- }
+template <typename T, typename U>
+void check_signed_range(bool negative, U value, const std::string &text)
+{
+ SignedCheck<T, std::numeric_limits<T>::is_signed>()(negative, value, text);
+}
+} // namespace detail
- const US next = static_cast<US>(result * base + digit);
- if (result > next)
- {
- throw_or_mimic<argument_incorrect_type>(text);
- }
+template <typename R, typename T>
+R checked_negate(T &&t, const std::string &, std::true_type)
+{
+ // if we got to here, then `t` is a positive number that fits into
+ // `R`. So to avoid MSVC C4146, we first cast it to `R`.
+ // See https://github.com/jarro2783/cxxopts/issues/62 for more details.
+ return static_cast<R>(-static_cast<R>(t - 1) - 1);
+}
- result = next;
- }
+template <typename R, typename T>
+T checked_negate(T &&t, const std::string &text, std::false_type)
+{
+ throw_or_mimic<argument_incorrect_type>(text);
+ return t;
+}
- detail::check_signed_range<T>(negative, result, text);
+template <typename T>
+void integer_parser(const std::string &text, T &value)
+{
+ std::smatch match;
+ std::regex_match(text, match, integer_pattern);
- if (negative)
- {
- value = checked_negate<T>(result,
- text,
- std::integral_constant<bool, is_signed>());
- }
- else
- {
- value = static_cast<T>(result);
- }
- }
+ if (match.length() == 0)
+ {
+ throw_or_mimic<argument_incorrect_type>(text);
+ }
- template <typename T>
- void stringstream_parser(const std::string& text, T& value)
- {
- std::stringstream in(text);
- in >> value;
- if (!in) {
- throw_or_mimic<argument_incorrect_type>(text);
- }
- }
+ if (match.length(4) > 0)
+ {
+ value = 0;
+ return;
+ }
- inline
- void
- parse_value(const std::string& text, uint8_t& value)
- {
- integer_parser(text, value);
- }
+ using US = typename std::make_unsigned<T>::type;
- inline
- void
- parse_value(const std::string& text, int8_t& value)
- {
- integer_parser(text, value);
- }
+ constexpr bool is_signed = std::numeric_limits<T>::is_signed;
+ const bool negative = match.length(1) > 0;
+ const uint8_t base = match.length(2) > 0 ? 16 : 10;
- inline
- void
- parse_value(const std::string& text, uint16_t& value)
- {
- integer_parser(text, value);
- }
+ auto value_match = match[3];
- inline
- void
- parse_value(const std::string& text, int16_t& value)
- {
- integer_parser(text, value);
- }
+ US result = 0;
- inline
- void
- parse_value(const std::string& text, uint32_t& value)
- {
- integer_parser(text, value);
- }
+ for (auto iter = value_match.first; iter != value_match.second; ++iter)
+ {
+ US digit = 0;
- inline
- void
- parse_value(const std::string& text, int32_t& value)
+ if (*iter >= '0' && *iter <= '9')
{
- integer_parser(text, value);
+ digit = static_cast<US>(*iter - '0');
}
-
- inline
- void
- parse_value(const std::string& text, uint64_t& value)
+ else if (base == 16 && *iter >= 'a' && *iter <= 'f')
{
- integer_parser(text, value);
+ digit = static_cast<US>(*iter - 'a' + 10);
}
-
- inline
- void
- parse_value(const std::string& text, int64_t& value)
+ else if (base == 16 && *iter >= 'A' && *iter <= 'F')
{
- integer_parser(text, value);
+ digit = static_cast<US>(*iter - 'A' + 10);
}
-
- inline
- void
- parse_value(const std::string& text, bool& value)
+ else
{
- std::smatch result;
- std::regex_match(text, result, truthy_pattern);
-
- if (!result.empty())
- {
- value = true;
- return;
- }
-
- std::regex_match(text, result, falsy_pattern);
- if (!result.empty())
- {
- value = false;
- return;
- }
-
throw_or_mimic<argument_incorrect_type>(text);
}
- inline
- void
- parse_value(const std::string& text, std::string& value)
+ const US next = static_cast<US>(result * base + digit);
+ if (result > next)
{
- value = text;
+ throw_or_mimic<argument_incorrect_type>(text);
}
- // The fallback parser. It uses the stringstream parser to parse all types
- // that have not been overloaded explicitly. It has to be placed in the
- // source code before all other more specialized templates.
- template <typename T>
- void
- parse_value(const std::string& text, T& value) {
- stringstream_parser(text, value);
- }
+ result = next;
+ }
- template <typename T>
- void
- parse_value(const std::string& text, std::vector<T>& value)
- {
- std::stringstream in(text);
- std::string token;
- while(in.eof() == false && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
- T v;
- parse_value(token, v);
- value.emplace_back(std::move(v));
- }
- }
+ detail::check_signed_range<T>(negative, result, text);
-#ifdef CXXOPTS_HAS_OPTIONAL
- template <typename T>
- void
- parse_value(const std::string& text, std::optional<T>& value)
+ if (negative)
{
- T result;
- parse_value(text, result);
- value = std::move(result);
+ value = checked_negate<T>(result,
+ text,
+ std::integral_constant<bool, is_signed>());
}
-#endif
+ else
+ {
+ value = static_cast<T>(result);
+ }
+}
- inline
- void parse_value(const std::string& text, char& c)
- {
- if (text.length() != 1)
- {
- throw_or_mimic<argument_incorrect_type>(text);
- }
+template <typename T>
+void stringstream_parser(const std::string &text, T &value)
+{
+ std::stringstream in(text);
+ in >> value;
+ if (!in)
+ {
+ throw_or_mimic<argument_incorrect_type>(text);
+ }
+}
- c = text[0];
- }
+inline void
+parse_value(const std::string &text, uint8_t &value)
+{
+ integer_parser(text, value);
+}
- template <typename T>
- struct type_is_container
- {
- static constexpr bool value = false;
- };
+inline void
+parse_value(const std::string &text, int8_t &value)
+{
+ integer_parser(text, value);
+}
- template <typename T>
- struct type_is_container<std::vector<T>>
- {
- static constexpr bool value = true;
- };
+inline void
+parse_value(const std::string &text, uint16_t &value)
+{
+ integer_parser(text, value);
+}
- template <typename T>
- class abstract_value : public Value
- {
- using Self = abstract_value<T>;
+inline void
+parse_value(const std::string &text, int16_t &value)
+{
+ integer_parser(text, value);
+}
- public:
- abstract_value()
- : m_result(std::make_shared<T>())
- , m_store(m_result.get())
- {
- }
+inline void
+parse_value(const std::string &text, uint32_t &value)
+{
+ integer_parser(text, value);
+}
- abstract_value(T* t)
- : m_store(t)
- {
- }
+inline void
+parse_value(const std::string &text, int32_t &value)
+{
+ integer_parser(text, value);
+}
- virtual ~abstract_value() = default;
+inline void
+parse_value(const std::string &text, uint64_t &value)
+{
+ integer_parser(text, value);
+}
- abstract_value(const abstract_value& rhs)
- {
- if (rhs.m_result)
- {
- m_result = std::make_shared<T>();
- m_store = m_result.get();
- }
- else
- {
- m_store = rhs.m_store;
- }
+inline void
+parse_value(const std::string &text, int64_t &value)
+{
+ integer_parser(text, value);
+}
- m_default = rhs.m_default;
- m_implicit = rhs.m_implicit;
- m_default_value = rhs.m_default_value;
- m_implicit_value = rhs.m_implicit_value;
- }
+inline void
+parse_value(const std::string &text, bool &value)
+{
+ std::smatch result;
+ std::regex_match(text, result, truthy_pattern);
- void
- parse(const std::string& text) const
- {
- parse_value(text, *m_store);
- }
+ if (!result.empty())
+ {
+ value = true;
+ return;
+ }
- bool
- is_container() const
- {
- return type_is_container<T>::value;
- }
+ std::regex_match(text, result, falsy_pattern);
+ if (!result.empty())
+ {
+ value = false;
+ return;
+ }
- void
- parse() const
- {
- parse_value(m_default_value, *m_store);
- }
+ throw_or_mimic<argument_incorrect_type>(text);
+}
- bool
- has_default() const
- {
- return m_default;
- }
+inline void
+parse_value(const std::string &text, std::string &value)
+{
+ value = text;
+}
- bool
- has_implicit() const
- {
- return m_implicit;
- }
+// The fallback parser. It uses the stringstream parser to parse all types
+// that have not been overloaded explicitly. It has to be placed in the
+// source code before all other more specialized templates.
+template <typename T>
+void parse_value(const std::string &text, T &value)
+{
+ stringstream_parser(text, value);
+}
- std::shared_ptr<Value>
- default_value(const std::string& value)
- {
- m_default = true;
- m_default_value = value;
- return shared_from_this();
- }
+template <typename T>
+void parse_value(const std::string &text, std::vector<T> &value)
+{
+ std::stringstream in(text);
+ std::string token;
+ while (in.eof() == false && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER))
+ {
+ T v;
+ parse_value(token, v);
+ value.emplace_back(std::move(v));
+ }
+}
- std::shared_ptr<Value>
- implicit_value(const std::string& value)
- {
- m_implicit = true;
- m_implicit_value = value;
- return shared_from_this();
- }
+#ifdef CXXOPTS_HAS_OPTIONAL
+template <typename T>
+void parse_value(const std::string &text, std::optional<T> &value)
+{
+ T result;
+ parse_value(text, result);
+ value = std::move(result);
+}
+#endif
- std::shared_ptr<Value>
- no_implicit_value()
- {
- m_implicit = false;
- return shared_from_this();
- }
+inline void parse_value(const std::string &text, char &c)
+{
+ if (text.length() != 1)
+ {
+ throw_or_mimic<argument_incorrect_type>(text);
+ }
- std::string
- get_default_value() const
- {
- return m_default_value;
- }
+ c = text[0];
+}
- std::string
- get_implicit_value() const
- {
- return m_implicit_value;
- }
+template <typename T>
+struct type_is_container
+{
+ static constexpr bool value = false;
+};
- bool
- is_boolean() const
- {
- return std::is_same<T, bool>::value;
- }
+template <typename T>
+struct type_is_container<std::vector<T>>
+{
+ static constexpr bool value = true;
+};
- const T&
- get() const
- {
- if (m_store == nullptr)
- {
- return *m_result;
- }
- else
- {
- return *m_store;
- }
- }
+template <typename T>
+class abstract_value : public Value
+{
+ using Self = abstract_value<T>;
- protected:
- std::shared_ptr<T> m_result;
- T* m_store;
+public:
+ abstract_value()
+ : m_result(std::make_shared<T>()), m_store(m_result.get())
+ {
+ }
- bool m_default = false;
- bool m_implicit = false;
+ abstract_value(T *t)
+ : m_store(t)
+ {
+ }
- std::string m_default_value;
- std::string m_implicit_value;
- };
+ virtual ~abstract_value() = default;
- template <typename T>
- class standard_value : public abstract_value<T>
+ abstract_value(const abstract_value &rhs)
+ {
+ if (rhs.m_result)
{
- public:
- using abstract_value<T>::abstract_value;
+ m_result = std::make_shared<T>();
+ m_store = m_result.get();
+ }
+ else
+ {
+ m_store = rhs.m_store;
+ }
- std::shared_ptr<Value>
- clone() const
- {
- return std::make_shared<standard_value<T>>(*this);
- }
- };
+ m_default = rhs.m_default;
+ m_implicit = rhs.m_implicit;
+ m_default_value = rhs.m_default_value;
+ m_implicit_value = rhs.m_implicit_value;
+ }
- template <>
- class standard_value<bool> : public abstract_value<bool>
- {
- public:
- ~standard_value() = default;
+ void
+ parse(const std::string &text) const
+ {
+ parse_value(text, *m_store);
+ }
- standard_value()
- {
- set_default_and_implicit();
- }
+ bool
+ is_container() const
+ {
+ return type_is_container<T>::value;
+ }
- standard_value(bool* b)
- : abstract_value(b)
- {
- set_default_and_implicit();
- }
+ void
+ parse() const
+ {
+ parse_value(m_default_value, *m_store);
+ }
- std::shared_ptr<Value>
- clone() const
- {
- return std::make_shared<standard_value<bool>>(*this);
- }
+ bool
+ has_default() const
+ {
+ return m_default;
+ }
- private:
+ bool
+ has_implicit() const
+ {
+ return m_implicit;
+ }
- void
- set_default_and_implicit()
- {
- m_default = true;
- m_default_value = "false";
- m_implicit = true;
- m_implicit_value = "true";
- }
- };
+ std::shared_ptr<Value>
+ default_value(const std::string &value)
+ {
+ m_default = true;
+ m_default_value = value;
+ return shared_from_this();
}
- template <typename T>
std::shared_ptr<Value>
- value()
+ implicit_value(const std::string &value)
{
- return std::make_shared<values::standard_value<T>>();
+ m_implicit = true;
+ m_implicit_value = value;
+ return shared_from_this();
}
- template <typename T>
std::shared_ptr<Value>
- value(T& t)
+ no_implicit_value()
{
- return std::make_shared<values::standard_value<T>>(&t);
+ m_implicit = false;
+ return shared_from_this();
}
- class OptionAdder;
+ std::string
+ get_default_value() const
+ {
+ return m_default_value;
+ }
- class OptionDetails
+ std::string
+ get_implicit_value() const
{
- public:
- OptionDetails
- (
- const std::string& short_,
- const std::string& long_,
- const String& desc,
- std::shared_ptr<const Value> val
- )
- : m_short(short_)
- , m_long(long_)
- , m_desc(desc)
- , m_value(val)
- , m_count(0)
+ return m_implicit_value;
+ }
+
+ bool
+ is_boolean() const
+ {
+ return std::is_same<T, bool>::value;
+ }
+
+ const T &
+ get() const
+ {
+ if (m_store == nullptr)
{
+ return *m_result;
}
-
- OptionDetails(const OptionDetails& rhs)
- : m_desc(rhs.m_desc)
- , m_count(rhs.m_count)
+ else
{
- m_value = rhs.m_value->clone();
+ return *m_store;
}
+ }
- OptionDetails(OptionDetails&& rhs) = default;
+protected:
+ std::shared_ptr<T> m_result;
+ T *m_store;
- const String&
- description() const
- {
- return m_desc;
- }
+ bool m_default = false;
+ bool m_implicit = false;
- const Value& value() const {
- return *m_value;
- }
+ std::string m_default_value;
+ std::string m_implicit_value;
+};
- std::shared_ptr<Value>
- make_storage() const
- {
- return m_value->clone();
- }
+template <typename T>
+class standard_value : public abstract_value<T>
+{
+public:
+ using abstract_value<T>::abstract_value;
- const std::string&
- short_name() const
- {
- return m_short;
- }
+ std::shared_ptr<Value>
+ clone() const
+ {
+ return std::make_shared<standard_value<T>>(*this);
+ }
+};
- const std::string&
- long_name() const
- {
- return m_long;
- }
+template <>
+class standard_value<bool> : public abstract_value<bool>
+{
+public:
+ ~standard_value() = default;
- private:
- std::string m_short;
- std::string m_long;
- String m_desc;
- std::shared_ptr<const Value> m_value;
- int m_count;
- };
-
- struct HelpOptionDetails
- {
- std::string s;
- std::string l;
- String desc;
- bool has_default;
- std::string default_value;
- bool has_implicit;
- std::string implicit_value;
- std::string arg_help;
- bool is_container;
- bool is_boolean;
- };
-
- struct HelpGroupDetails
- {
- std::string name;
- std::string description;
- std::vector<HelpOptionDetails> options;
- };
-
- class OptionValue
- {
- public:
- void
- parse
- (
- std::shared_ptr<const OptionDetails> details,
- const std::string& text
- )
- {
- ensure_value(details);
- ++m_count;
- m_value->parse(text);
- }
+ standard_value()
+ {
+ set_default_and_implicit();
+ }
- void
- parse_default(std::shared_ptr<const OptionDetails> details)
- {
- ensure_value(details);
- m_default = true;
- m_value->parse();
- }
+ standard_value(bool *b)
+ : abstract_value(b)
+ {
+ set_default_and_implicit();
+ }
- size_t
- count() const noexcept
- {
- return m_count;
- }
+ std::shared_ptr<Value>
+ clone() const
+ {
+ return std::make_shared<standard_value<bool>>(*this);
+ }
- // TODO: maybe default options should count towards the number of arguments
- bool
- has_default() const noexcept
- {
- return m_default;
- }
+private:
+ void
+ set_default_and_implicit()
+ {
+ m_default = true;
+ m_default_value = "false";
+ m_implicit = true;
+ m_implicit_value = "true";
+ }
+};
+} // namespace values
- template <typename T>
- const T&
- as() const
- {
- if (m_value == nullptr) {
- throw_or_mimic<std::domain_error>("No value");
- }
+template <typename T>
+std::shared_ptr<Value>
+value()
+{
+ return std::make_shared<values::standard_value<T>>();
+}
-#ifdef CXXOPTS_NO_RTTI
- return static_cast<const values::standard_value<T>&>(*m_value).get();
-#else
- return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
-#endif
- }
+template <typename T>
+std::shared_ptr<Value>
+value(T &t)
+{
+ return std::make_shared<values::standard_value<T>>(&t);
+}
- private:
- void
- ensure_value(std::shared_ptr<const OptionDetails> details)
- {
- if (m_value == nullptr)
- {
- m_value = details->make_storage();
- }
- }
+class OptionAdder;
- std::shared_ptr<Value> m_value;
- size_t m_count = 0;
- bool m_default = false;
- };
+class OptionDetails
+{
+public:
+ OptionDetails(
+ const std::string &short_,
+ const std::string &long_,
+ const String &desc,
+ std::shared_ptr<const Value> val)
+ : m_short(short_), m_long(long_), m_desc(desc), m_value(val), m_count(0)
+ {
+ }
- class KeyValue
+ OptionDetails(const OptionDetails &rhs)
+ : m_desc(rhs.m_desc), m_count(rhs.m_count)
{
- public:
- KeyValue(std::string key_, std::string value_)
- : m_key(std::move(key_))
- , m_value(std::move(value_))
- {
- }
+ m_value = rhs.m_value->clone();
+ }
- const
- std::string&
- key() const
- {
- return m_key;
- }
+ OptionDetails(OptionDetails &&rhs) = default;
- const
- std::string&
- value() const
- {
- return m_value;
- }
+ const String &
+ description() const
+ {
+ return m_desc;
+ }
- template <typename T>
- T
- as() const
- {
- T result;
- values::parse_value(m_value, result);
- return result;
- }
+ const Value &value() const
+ {
+ return *m_value;
+ }
- private:
- std::string m_key;
- std::string m_value;
- };
+ std::shared_ptr<Value>
+ make_storage() const
+ {
+ return m_value->clone();
+ }
- class ParseResult
+ const std::string &
+ short_name() const
{
- public:
+ return m_short;
+ }
- ParseResult(
- const std::shared_ptr<
- std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
- >,
- std::vector<std::string>,
- bool allow_unrecognised,
- int&, char**&);
+ const std::string &
+ long_name() const
+ {
+ return m_long;
+ }
- size_t
- count(const std::string& o) const
- {
- auto iter = m_options->find(o);
- if (iter == m_options->end())
- {
- return 0;
- }
+private:
+ std::string m_short;
+ std::string m_long;
+ String m_desc;
+ std::shared_ptr<const Value> m_value;
+ int m_count;
+};
- auto riter = m_results.find(iter->second);
+struct HelpOptionDetails
+{
+ std::string s;
+ std::string l;
+ String desc;
+ bool has_default;
+ std::string default_value;
+ bool has_implicit;
+ std::string implicit_value;
+ std::string arg_help;
+ bool is_container;
+ bool is_boolean;
+};
+
+struct HelpGroupDetails
+{
+ std::string name;
+ std::string description;
+ std::vector<HelpOptionDetails> options;
+};
- return riter->second.count();
- }
+class OptionValue
+{
+public:
+ void
+ parse(
+ std::shared_ptr<const OptionDetails> details,
+ const std::string &text)
+ {
+ ensure_value(details);
+ ++m_count;
+ m_value->parse(text);
+ }
- const OptionValue&
- operator[](const std::string& option) const
- {
- auto iter = m_options->find(option);
+ void
+ parse_default(std::shared_ptr<const OptionDetails> details)
+ {
+ ensure_value(details);
+ m_default = true;
+ m_value->parse();
+ }
- if (iter == m_options->end())
- {
- throw_or_mimic<option_not_present_exception>(option);
- }
+ size_t
+ count() const noexcept
+ {
+ return m_count;
+ }
- auto riter = m_results.find(iter->second);
+ // TODO: maybe default options should count towards the number of arguments
+ bool
+ has_default() const noexcept
+ {
+ return m_default;
+ }
- return riter->second;
+ template <typename T>
+ const T &
+ as() const
+ {
+ if (m_value == nullptr)
+ {
+ throw_or_mimic<std::domain_error>("No value");
}
- const std::vector<KeyValue>&
- arguments() const
+#ifdef CXXOPTS_NO_RTTI
+ return static_cast<const values::standard_value<T> &>(*m_value).get();
+#else
+ return dynamic_cast<const values::standard_value<T> &>(*m_value).get();
+#endif
+ }
+
+private:
+ void
+ ensure_value(std::shared_ptr<const OptionDetails> details)
+ {
+ if (m_value == nullptr)
{
- return m_sequential;
+ m_value = details->make_storage();
}
+ }
- private:
-
- void
- parse(int& argc, char**& argv);
+ std::shared_ptr<Value> m_value;
+ size_t m_count = 0;
+ bool m_default = false;
+};
- void
- add_to_option(const std::string& option, const std::string& arg);
+class KeyValue
+{
+public:
+ KeyValue(std::string key_, std::string value_)
+ : m_key(std::move(key_)), m_value(std::move(value_))
+ {
+ }
- bool
- consume_positional(std::string a);
+ const std::string &
+ key() const
+ {
+ return m_key;
+ }
- void
- parse_option
- (
- std::shared_ptr<OptionDetails> value,
- const std::string& name,
- const std::string& arg = ""
- );
+ const std::string &
+ value() const
+ {
+ return m_value;
+ }
- void
- parse_default(std::shared_ptr<OptionDetails> details);
+ template <typename T>
+ T as() const
+ {
+ T result;
+ values::parse_value(m_value, result);
+ return result;
+ }
- void
- checked_parse_arg
- (
- int argc,
- char* argv[],
- int& current,
- std::shared_ptr<OptionDetails> value,
- const std::string& name
- );
+private:
+ std::string m_key;
+ std::string m_value;
+};
+class ParseResult
+{
+public:
+ ParseResult(
const std::shared_ptr<
- std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
- > m_options;
- std::vector<std::string> m_positional;
- std::vector<std::string>::iterator m_next_positional;
- std::unordered_set<std::string> m_positional_set;
- std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results;
-
- bool m_allow_unrecognised;
-
- std::vector<KeyValue> m_sequential;
- };
-
- struct Option
- {
- Option
- (
- const std::string& opts,
- const std::string& desc,
- const std::shared_ptr<const Value>& value = ::cxxopts::value<bool>(),
- const std::string& arg_help = ""
- )
- : opts_(opts)
- , desc_(desc)
- , value_(value)
- , arg_help_(arg_help)
- {
- }
+ std::unordered_map<std::string, std::shared_ptr<OptionDetails>>>,
+ std::vector<std::string>,
+ bool allow_unrecognised,
+ int &, char **&);
- std::string opts_;
- std::string desc_;
- std::shared_ptr<const Value> value_;
- std::string arg_help_;
- };
-
- class Options
- {
- typedef std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
- OptionMap;
- public:
-
- Options(std::string program, std::string help_string = "")
- : m_program(std::move(program))
- , m_help_string(toLocalString(std::move(help_string)))
- , m_custom_help("[OPTION...]")
- , m_positional_help("positional parameters")
- , m_show_positional(false)
- , m_allow_unrecognised(false)
- , m_options(std::make_shared<OptionMap>())
- , m_next_positional(m_positional.end())
+ size_t
+ count(const std::string &o) const
+ {
+ auto iter = m_options->find(o);
+ if (iter == m_options->end())
{
+ return 0;
}
- Options&
- positional_help(std::string help_text)
- {
- m_positional_help = std::move(help_text);
- return *this;
- }
+ auto riter = m_results.find(iter->second);
- Options&
- custom_help(std::string help_text)
- {
- m_custom_help = std::move(help_text);
- return *this;
- }
+ return riter->second.count();
+ }
- Options&
- show_positional_help()
- {
- m_show_positional = true;
- return *this;
- }
+ const OptionValue &
+ operator[](const std::string &option) const
+ {
+ auto iter = m_options->find(option);
- Options&
- allow_unrecognised_options()
+ if (iter == m_options->end())
{
- m_allow_unrecognised = true;
- return *this;
+ throw_or_mimic<option_not_present_exception>(option);
}
- ParseResult
- parse(int& argc, char**& argv);
-
- OptionAdder
- add_options(std::string group = "");
-
- void
- add_options
- (
- const std::string& group,
- std::initializer_list<Option> options
- );
-
- void
- add_option
- (
- const std::string& group,
- const Option& option
- );
-
- 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
- );
-
- //parse positional arguments into the given option
- void
- parse_positional(std::string option);
-
- void
- parse_positional(std::vector<std::string> options);
-
- void
- parse_positional(std::initializer_list<std::string> options);
-
- template <typename Iterator>
- void
- parse_positional(Iterator begin, Iterator end) {
- parse_positional(std::vector<std::string>{begin, end});
- }
+ auto riter = m_results.find(iter->second);
- std::string
- help(const std::vector<std::string>& groups = {}) const;
+ return riter->second;
+ }
- const std::vector<std::string>
- groups() const;
+ const std::vector<KeyValue> &
+ arguments() const
+ {
+ return m_sequential;
+ }
- const HelpGroupDetails&
- group_help(const std::string& group) const;
+private:
+ void
+ parse(int &argc, char **&argv);
- private:
+ void
+ add_to_option(const std::string &option, const std::string &arg);
- void
- add_one_option
- (
- const std::string& option,
- std::shared_ptr<OptionDetails> details
- );
+ bool
+ consume_positional(std::string a);
- String
- help_one_group(const std::string& group) const;
+ void
+ parse_option(
+ std::shared_ptr<OptionDetails> value,
+ const std::string &name,
+ const std::string &arg = "");
- void
- generate_group_help
- (
- String& result,
- const std::vector<std::string>& groups
- ) const;
+ void
+ parse_default(std::shared_ptr<OptionDetails> details);
- void
- generate_all_groups_help(String& result) const;
+ void
+ checked_parse_arg(
+ int argc,
+ char *argv[],
+ int &current,
+ std::shared_ptr<OptionDetails> value,
+ const std::string &name);
+
+ const std::shared_ptr<
+ std::unordered_map<std::string, std::shared_ptr<OptionDetails>>>
+ m_options;
+ std::vector<std::string> m_positional;
+ std::vector<std::string>::iterator m_next_positional;
+ std::unordered_set<std::string> m_positional_set;
+ std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results;
+
+ bool m_allow_unrecognised;
+
+ std::vector<KeyValue> m_sequential;
+};
+
+struct Option
+{
+ Option(
+ const std::string &opts,
+ const std::string &desc,
+ const std::shared_ptr<const Value> &value = ::cxxopts::value<bool>(),
+ const std::string &arg_help = "")
+ : opts_(opts), desc_(desc), value_(value), arg_help_(arg_help)
+ {
+ }
- std::string m_program;
- String m_help_string;
- std::string m_custom_help;
- std::string m_positional_help;
- bool m_show_positional;
- bool m_allow_unrecognised;
+ std::string opts_;
+ std::string desc_;
+ std::shared_ptr<const Value> value_;
+ std::string arg_help_;
+};
- std::shared_ptr<OptionMap> m_options;
- std::vector<std::string> m_positional;
- std::vector<std::string>::iterator m_next_positional;
- std::unordered_set<std::string> m_positional_set;
+class Options
+{
+ typedef std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
+ OptionMap;
- //mapping from groups to help options
- std::map<std::string, HelpGroupDetails> m_help;
- };
+public:
+ Options(std::string program, std::string help_string = "")
+ : m_program(std::move(program)), m_help_string(toLocalString(std::move(help_string))), m_custom_help("[OPTION...]"), m_positional_help("positional parameters"), m_show_positional(false), m_allow_unrecognised(false), m_options(std::make_shared<OptionMap>()), m_next_positional(m_positional.end())
+ {
+ }
- class OptionAdder
+ Options &
+ positional_help(std::string help_text)
{
- public:
+ m_positional_help = std::move(help_text);
+ return *this;
+ }
- OptionAdder(Options& options, std::string group)
- : m_options(options), m_group(std::move(group))
- {
- }
+ Options &
+ custom_help(std::string help_text)
+ {
+ m_custom_help = std::move(help_text);
+ return *this;
+ }
- OptionAdder&
- operator()
- (
- const std::string& opts,
- const std::string& desc,
- std::shared_ptr<const Value> value
- = ::cxxopts::value<bool>(),
- std::string arg_help = ""
- );
-
- private:
- Options& m_options;
- std::string m_group;
- };
-
- namespace
- {
- constexpr int OPTION_LONGEST = 30;
- constexpr int OPTION_DESC_GAP = 2;
-
- std::basic_regex<char> option_matcher
- ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
-
- std::basic_regex<char> option_specifier
- ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
-
- String
- format_option
- (
- const HelpOptionDetails& o
- )
- {
- auto& s = o.s;
- auto& l = o.l;
+ Options &
+ show_positional_help()
+ {
+ m_show_positional = true;
+ return *this;
+ }
- String result = " ";
+ Options &
+ allow_unrecognised_options()
+ {
+ m_allow_unrecognised = true;
+ return *this;
+ }
- if (s.size() > 0)
- {
- result += "-" + toLocalString(s) + ",";
- }
- else
- {
- result += " ";
- }
+ ParseResult
+ parse(int &argc, char **&argv);
- if (l.size() > 0)
- {
- result += " --" + toLocalString(l);
- }
+ OptionAdder
+ add_options(std::string group = "");
- auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg";
+ void
+ add_options(
+ const std::string &group,
+ std::initializer_list<Option> options);
- if (!o.is_boolean)
- {
- if (o.has_implicit)
- {
- result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
- }
- else
- {
- result += " " + arg;
- }
- }
+ void
+ add_option(
+ const std::string &group,
+ const Option &option);
- return result;
- }
+ 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);
+
+ //parse positional arguments into the given option
+ void
+ parse_positional(std::string option);
- String
- format_description
- (
- const HelpOptionDetails& o,
- size_t start,
- size_t width
- )
- {
- auto desc = o.desc;
+ void
+ parse_positional(std::vector<std::string> options);
- if (o.has_default && (!o.is_boolean || o.default_value != "false"))
- {
- if(o.default_value != "")
- {
- desc += toLocalString(" (default: " + o.default_value + ")");
- }
- else
- {
- desc += toLocalString(" (default: \"\")");
- }
- }
+ void
+ parse_positional(std::initializer_list<std::string> options);
- String result;
+ template <typename Iterator>
+ void
+ parse_positional(Iterator begin, Iterator end)
+ {
+ parse_positional(std::vector<std::string>{begin, end});
+ }
- auto current = std::begin(desc);
- auto startLine = current;
- auto lastSpace = current;
+ std::string
+ help(const std::vector<std::string> &groups = {}) const;
- auto size = size_t{};
+ const std::vector<std::string>
+ groups() const;
- while (current != std::end(desc))
- {
- if (*current == ' ')
- {
- lastSpace = current;
- }
+ const HelpGroupDetails &
+ group_help(const std::string &group) const;
- if (*current == '\n')
- {
- startLine = current + 1;
- lastSpace = startLine;
- }
- else if (size > width)
- {
- if (lastSpace == startLine)
- {
- stringAppend(result, startLine, current + 1);
- stringAppend(result, "\n");
- stringAppend(result, start, ' ');
- startLine = current + 1;
- lastSpace = startLine;
- }
- else
- {
- stringAppend(result, startLine, lastSpace);
- stringAppend(result, "\n");
- stringAppend(result, start, ' ');
- startLine = lastSpace + 1;
- lastSpace = startLine;
- }
- size = 0;
- }
- else
- {
- ++size;
- }
+private:
+ void
+ add_one_option(
+ const std::string &option,
+ std::shared_ptr<OptionDetails> details);
- ++current;
- }
+ String
+ help_one_group(const std::string &group) const;
- //append whatever is left
- stringAppend(result, startLine, current);
+ void
+ generate_group_help(
+ String &result,
+ const std::vector<std::string> &groups) const;
- return result;
- }
- }
+ void
+ generate_all_groups_help(String &result) const;
+
+ std::string m_program;
+ String m_help_string;
+ std::string m_custom_help;
+ std::string m_positional_help;
+ bool m_show_positional;
+ bool m_allow_unrecognised;
+
+ std::shared_ptr<OptionMap> m_options;
+ std::vector<std::string> m_positional;
+ std::vector<std::string>::iterator m_next_positional;
+ std::unordered_set<std::string> m_positional_set;
+
+ //mapping from groups to help options
+ std::map<std::string, HelpGroupDetails> m_help;
+};
- inline
- ParseResult::ParseResult
- (
- const std::shared_ptr<
- std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
- > options,
- std::vector<std::string> positional,
- bool allow_unrecognised,
- int& argc, char**& argv
- )
- : m_options(options)
- , m_positional(std::move(positional))
- , m_next_positional(m_positional.begin())
- , m_allow_unrecognised(allow_unrecognised)
+class OptionAdder
+{
+public:
+ OptionAdder(Options &options, std::string group)
+ : m_options(options), m_group(std::move(group))
{
- parse(argc, argv);
}
- inline
- void
- Options::add_options
- (
- const std::string &group,
- std::initializer_list<Option> options
- )
- {
- OptionAdder option_adder(*this, group);
- for (const auto &option: options)
- {
- option_adder(option.opts_, option.desc_, option.value_, option.arg_help_);
- }
- }
+ OptionAdder &
+ operator()(
+ const std::string &opts,
+ const std::string &desc,
+ std::shared_ptr<const Value> value = ::cxxopts::value<bool>(),
+ std::string arg_help = "");
- inline
- OptionAdder
- Options::add_options(std::string group)
+private:
+ Options &m_options;
+ std::string m_group;
+};
+
+namespace
+{
+constexpr int OPTION_LONGEST = 30;
+constexpr int OPTION_DESC_GAP = 2;
+
+std::basic_regex<char> option_matcher("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
+
+std::basic_regex<char> option_specifier("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
+
+String
+format_option(
+ const HelpOptionDetails &o)
+{
+ auto &s = o.s;
+ auto &l = o.l;
+
+ String result = " ";
+
+ if (s.size() > 0)
+ {
+ result += "-" + toLocalString(s) + ",";
+ }
+ else
{
- return OptionAdder(*this, std::move(group));
+ result += " ";
}
- inline
- OptionAdder&
- OptionAdder::operator()
- (
- const std::string& opts,
- const std::string& desc,
- std::shared_ptr<const Value> value,
- std::string arg_help
- )
+ if (l.size() > 0)
{
- std::match_results<const char*> result;
- std::regex_match(opts.c_str(), result, option_specifier);
+ result += " --" + toLocalString(l);
+ }
- if (result.empty())
+ auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg";
+
+ if (!o.is_boolean)
+ {
+ if (o.has_implicit)
+ {
+ result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
+ }
+ else
{
- throw_or_mimic<invalid_option_format_error>(opts);
+ result += " " + arg;
}
+ }
- const auto& short_match = result[2];
- const auto& long_match = result[3];
+ return result;
+}
- if (!short_match.length() && !long_match.length())
+String
+format_description(
+ const HelpOptionDetails &o,
+ size_t start,
+ size_t width)
+{
+ auto desc = o.desc;
+
+ if (o.has_default && (!o.is_boolean || o.default_value != "false"))
+ {
+ if (o.default_value != "")
{
- throw_or_mimic<invalid_option_format_error>(opts);
- } else if (long_match.length() == 1 && short_match.length())
+ desc += toLocalString(" (default: " + o.default_value + ")");
+ }
+ else
+ {
+ desc += toLocalString(" (default: \"\")");
+ }
+ }
+
+ String result;
+
+ auto current = std::begin(desc);
+ auto startLine = current;
+ auto lastSpace = current;
+
+ auto size = size_t{};
+
+ while (current != std::end(desc))
+ {
+ if (*current == ' ')
{
- throw_or_mimic<invalid_option_format_error>(opts);
+ lastSpace = current;
}
- auto option_names = []
- (
- const std::sub_match<const char*>& short_,
- const std::sub_match<const char*>& long_
- )
+ if (*current == '\n')
+ {
+ startLine = current + 1;
+ lastSpace = startLine;
+ }
+ else if (size > width)
{
- if (long_.length() == 1)
+ if (lastSpace == startLine)
{
- return std::make_tuple(long_.str(), short_.str());
+ stringAppend(result, startLine, current + 1);
+ stringAppend(result, "\n");
+ stringAppend(result, start, ' ');
+ startLine = current + 1;
+ lastSpace = startLine;
}
else
{
- return std::make_tuple(short_.str(), long_.str());
+ stringAppend(result, startLine, lastSpace);
+ stringAppend(result, "\n");
+ stringAppend(result, start, ' ');
+ startLine = lastSpace + 1;
+ lastSpace = startLine;
}
- }(short_match, long_match);
-
- m_options.add_option
- (
- m_group,
- std::get<0>(option_names),
- std::get<1>(option_names),
- desc,
- value,
- std::move(arg_help)
- );
+ size = 0;
+ }
+ else
+ {
+ ++size;
+ }
- return *this;
+ ++current;
}
- inline
- void
- ParseResult::parse_default(std::shared_ptr<OptionDetails> details)
+ //append whatever is left
+ stringAppend(result, startLine, current);
+
+ return result;
+}
+} // namespace
+
+inline ParseResult::ParseResult(
+ const std::shared_ptr<
+ std::unordered_map<std::string, std::shared_ptr<OptionDetails>>>
+ options,
+ std::vector<std::string> positional,
+ bool allow_unrecognised,
+ int &argc, char **&argv)
+ : m_options(options), m_positional(std::move(positional)), m_next_positional(m_positional.begin()), m_allow_unrecognised(allow_unrecognised)
+{
+ parse(argc, argv);
+}
+
+inline void
+Options::add_options(
+ const std::string &group,
+ std::initializer_list<Option> options)
+{
+ OptionAdder option_adder(*this, group);
+ for (const auto &option : options)
{
- m_results[details].parse_default(details);
+ option_adder(option.opts_, option.desc_, option.value_, option.arg_help_);
}
+}
- inline
- void
- ParseResult::parse_option
- (
- std::shared_ptr<OptionDetails> value,
- const std::string& /*name*/,
- const std::string& arg
- )
+inline OptionAdder
+Options::add_options(std::string group)
+{
+ return OptionAdder(*this, std::move(group));
+}
+
+inline OptionAdder &
+OptionAdder::operator()(
+ const std::string &opts,
+ const std::string &desc,
+ std::shared_ptr<const Value> value,
+ std::string arg_help)
+{
+ std::match_results<const char *> result;
+ std::regex_match(opts.c_str(), result, option_specifier);
+
+ if (result.empty())
{
- auto& result = m_results[value];
- result.parse(value, arg);
+ throw_or_mimic<invalid_option_format_error>(opts);
+ }
+
+ const auto &short_match = result[2];
+ const auto &long_match = result[3];
- m_sequential.emplace_back(value->long_name(), arg);
+ if (!short_match.length() && !long_match.length())
+ {
+ throw_or_mimic<invalid_option_format_error>(opts);
+ }
+ else if (long_match.length() == 1 && short_match.length())
+ {
+ throw_or_mimic<invalid_option_format_error>(opts);
}
- inline
- void
- ParseResult::checked_parse_arg
- (
- int argc,
- char* argv[],
- int& current,
- std::shared_ptr<OptionDetails> value,
- const std::string& name
- )
- {
- if (current + 1 >= argc)
+ auto option_names = [](
+ const std::sub_match<const char *> &short_,
+ const std::sub_match<const char *> &long_) {
+ if (long_.length() == 1)
{
- if (value->value().has_implicit())
- {
- parse_option(value, name, value->value().get_implicit_value());
- }
- else
- {
- throw_or_mimic<missing_argument_exception>(name);
- }
+ return std::make_tuple(long_.str(), short_.str());
}
else
{
- if (value->value().has_implicit())
- {
- parse_option(value, name, value->value().get_implicit_value());
- }
- else
- {
- parse_option(value, name, argv[current + 1]);
- ++current;
- }
+ return std::make_tuple(short_.str(), long_.str());
}
- }
+ }(short_match, long_match);
- inline
- void
- ParseResult::add_to_option(const std::string& option, const std::string& arg)
- {
- auto iter = m_options->find(option);
+ m_options.add_option(
+ m_group,
+ std::get<0>(option_names),
+ std::get<1>(option_names),
+ desc,
+ value,
+ std::move(arg_help));
- if (iter == m_options->end())
+ return *this;
+}
+
+inline void
+ParseResult::parse_default(std::shared_ptr<OptionDetails> details)
+{
+ m_results[details].parse_default(details);
+}
+
+inline void
+ParseResult::parse_option(
+ std::shared_ptr<OptionDetails> value,
+ const std::string & /*name*/,
+ const std::string &arg)
+{
+ auto &result = m_results[value];
+ result.parse(value, arg);
+
+ m_sequential.emplace_back(value->long_name(), arg);
+}
+
+inline void
+ParseResult::checked_parse_arg(
+ int argc,
+ char *argv[],
+ int &current,
+ std::shared_ptr<OptionDetails> value,
+ const std::string &name)
+{
+ if (current + 1 >= argc)
+ {
+ if (value->value().has_implicit())
+ {
+ parse_option(value, name, value->value().get_implicit_value());
+ }
+ else
{
- throw_or_mimic<option_not_exists_exception>(option);
+ throw_or_mimic<missing_argument_exception>(name);
}
+ }
+ else
+ {
+ if (value->value().has_implicit())
+ {
+ parse_option(value, name, value->value().get_implicit_value());
+ }
+ else
+ {
+ parse_option(value, name, argv[current + 1]);
+ ++current;
+ }
+ }
+}
- parse_option(iter->second, option, arg);
+inline void
+ParseResult::add_to_option(const std::string &option, const std::string &arg)
+{
+ auto iter = m_options->find(option);
+
+ if (iter == m_options->end())
+ {
+ throw_or_mimic<option_not_exists_exception>(option);
}
- inline
- bool
- ParseResult::consume_positional(std::string a)
+ parse_option(iter->second, option, arg);
+}
+
+inline bool
+ParseResult::consume_positional(std::string a)
+{
+ while (m_next_positional != m_positional.end())
{
- while (m_next_positional != m_positional.end())
+ auto iter = m_options->find(*m_next_positional);
+ if (iter != m_options->end())
{
- auto iter = m_options->find(*m_next_positional);
- if (iter != m_options->end())
+ auto &result = m_results[iter->second];
+ if (!iter->second->value().is_container())
{
- auto& result = m_results[iter->second];
- if (!iter->second->value().is_container())
+ if (result.count() == 0)
{
- if (result.count() == 0)
- {
- add_to_option(*m_next_positional, a);
- ++m_next_positional;
- return true;
- }
- else
- {
- ++m_next_positional;
- continue;
- }
+ add_to_option(*m_next_positional, a);
+ ++m_next_positional;
+ return true;
}
else
{
- add_to_option(*m_next_positional, a);
- return true;
+ ++m_next_positional;
+ continue;
}
}
else
{
- throw_or_mimic<option_not_exists_exception>(*m_next_positional);
+ add_to_option(*m_next_positional, a);
+ return true;
}
}
-
- return false;
+ else
+ {
+ throw_or_mimic<option_not_exists_exception>(*m_next_positional);
+ }
}
- inline
- void
- Options::parse_positional(std::string option)
- {
- parse_positional(std::vector<std::string>{std::move(option)});
- }
+ return false;
+}
- inline
- void
- Options::parse_positional(std::vector<std::string> options)
- {
- m_positional = std::move(options);
- m_next_positional = m_positional.begin();
+inline void
+Options::parse_positional(std::string option)
+{
+ parse_positional(std::vector<std::string>{std::move(option)});
+}
- m_positional_set.insert(m_positional.begin(), m_positional.end());
- }
+inline void
+Options::parse_positional(std::vector<std::string> options)
+{
+ m_positional = std::move(options);
+ m_next_positional = m_positional.begin();
- inline
- void
- Options::parse_positional(std::initializer_list<std::string> options)
- {
- parse_positional(std::vector<std::string>(std::move(options)));
- }
+ m_positional_set.insert(m_positional.begin(), m_positional.end());
+}
- inline
- ParseResult
- Options::parse(int& argc, char**& argv)
- {
- ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv);
- return result;
- }
+inline void
+Options::parse_positional(std::initializer_list<std::string> options)
+{
+ parse_positional(std::vector<std::string>(std::move(options)));
+}
- inline
- void
- ParseResult::parse(int& argc, char**& argv)
- {
- int current = 1;
+inline ParseResult
+Options::parse(int &argc, char **&argv)
+{
+ ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv);
+ return result;
+}
- int nextKeep = 1;
+inline void
+ParseResult::parse(int &argc, char **&argv)
+{
+ int current = 1;
- bool consume_remaining = false;
+ int nextKeep = 1;
- while (current != argc)
- {
- if (strcmp(argv[current], "--") == 0)
- {
- consume_remaining = true;
- ++current;
- break;
- }
+ bool consume_remaining = false;
- std::match_results<const char*> result;
- std::regex_match(argv[current], result, option_matcher);
+ while (current != argc)
+ {
+ if (strcmp(argv[current], "--") == 0)
+ {
+ consume_remaining = true;
+ ++current;
+ break;
+ }
- if (result.empty())
- {
- //not a flag
+ std::match_results<const char *> result;
+ std::regex_match(argv[current], result, option_matcher);
- // but if it starts with a `-`, then it's an error
- if (argv[current][0] == '-' && argv[current][1] != '\0') {
- if (!m_allow_unrecognised) {
- throw_or_mimic<option_syntax_exception>(argv[current]);
- }
- }
+ if (result.empty())
+ {
+ //not a flag
- //if true is returned here then it was consumed, otherwise it is
- //ignored
- if (consume_positional(argv[current]))
- {
- }
- else
+ // but if it starts with a `-`, then it's an error
+ if (argv[current][0] == '-' && argv[current][1] != '\0')
+ {
+ if (!m_allow_unrecognised)
{
- argv[nextKeep] = argv[current];
- ++nextKeep;
+ throw_or_mimic<option_syntax_exception>(argv[current]);
}
- //if we return from here then it was parsed successfully, so continue
+ }
+
+ //if true is returned here then it was consumed, otherwise it is
+ //ignored
+ if (consume_positional(argv[current]))
+ {
}
else
{
- //short or long option?
- if (result[4].length() != 0)
- {
- const std::string& s = result[4];
-
- for (std::size_t i = 0; i != s.size(); ++i)
- {
- std::string name(1, s[i]);
- auto iter = m_options->find(name);
-
- if (iter == m_options->end())
- {
- if (m_allow_unrecognised)
- {
- continue;
- }
- else
- {
- //error
- throw_or_mimic<option_not_exists_exception>(name);
- }
- }
-
- auto value = iter->second;
+ argv[nextKeep] = argv[current];
+ ++nextKeep;
+ }
+ //if we return from here then it was parsed successfully, so continue
+ }
+ else
+ {
+ //short or long option?
+ if (result[4].length() != 0)
+ {
+ const std::string &s = result[4];
- if (i + 1 == s.size())
- {
- //it must be the last argument
- checked_parse_arg(argc, argv, current, value, name);
- }
- else if (value->value().has_implicit())
- {
- parse_option(value, name, value->value().get_implicit_value());
- }
- else
- {
- //error
- throw_or_mimic<option_requires_argument_exception>(name);
- }
- }
- }
- else if (result[1].length() != 0)
+ for (std::size_t i = 0; i != s.size(); ++i)
{
- const std::string& name = result[1];
-
+ std::string name(1, s[i]);
auto iter = m_options->find(name);
if (iter == m_options->end())
{
if (m_allow_unrecognised)
{
- // keep unrecognised options in argument list, skip to next argument
- argv[nextKeep] = argv[current];
- ++nextKeep;
- ++current;
continue;
}
else
@@ -1930,286 +1763,310 @@ namespace cxxopts
}
}
- auto opt = iter->second;
+ auto value = iter->second;
- //equals provided for long option?
- if (result[2].length() != 0)
+ if (i + 1 == s.size())
{
- //parse the option given
-
- parse_option(opt, name, result[3]);
+ //it must be the last argument
+ checked_parse_arg(argc, argv, current, value, name);
+ }
+ else if (value->value().has_implicit())
+ {
+ parse_option(value, name, value->value().get_implicit_value());
}
else
{
- //parse the next argument
- checked_parse_arg(argc, argv, current, opt, name);
+ //error
+ throw_or_mimic<option_requires_argument_exception>(name);
}
}
-
}
+ else if (result[1].length() != 0)
+ {
+ const std::string &name = result[1];
- ++current;
- }
+ auto iter = m_options->find(name);
- for (auto& opt : *m_options)
- {
- auto& detail = opt.second;
- auto& value = detail->value();
+ if (iter == m_options->end())
+ {
+ if (m_allow_unrecognised)
+ {
+ // keep unrecognised options in argument list, skip to next argument
+ argv[nextKeep] = argv[current];
+ ++nextKeep;
+ ++current;
+ continue;
+ }
+ else
+ {
+ //error
+ throw_or_mimic<option_not_exists_exception>(name);
+ }
+ }
- auto& store = m_results[detail];
+ auto opt = iter->second;
- if(value.has_default() && !store.count() && !store.has_default()){
- parse_default(detail);
- }
- }
+ //equals provided for long option?
+ if (result[2].length() != 0)
+ {
+ //parse the option given
- if (consume_remaining)
- {
- while (current < argc)
- {
- if (!consume_positional(argv[current])) {
- break;
+ parse_option(opt, name, result[3]);
+ }
+ else
+ {
+ //parse the next argument
+ checked_parse_arg(argc, argv, current, opt, name);
}
- ++current;
- }
-
- //adjust argv for any that couldn't be swallowed
- while (current != argc) {
- argv[nextKeep] = argv[current];
- ++nextKeep;
- ++current;
}
}
- argc = nextKeep;
-
+ ++current;
}
- inline
- void
- Options::add_option
- (
- const std::string& group,
- const Option& option
- )
+ for (auto &opt : *m_options)
{
- add_options(group, {option});
- }
+ auto &detail = opt.second;
+ auto &value = detail->value();
- inline
- void
- Options::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
- )
- {
- auto stringDesc = toLocalString(std::move(desc));
- auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);
-
- if (s.size() > 0)
- {
- add_one_option(s, option);
- }
+ auto &store = m_results[detail];
- if (l.size() > 0)
+ if (value.has_default() && !store.count() && !store.has_default())
{
- add_one_option(l, option);
+ parse_default(detail);
}
-
- //add the help details
- auto& options = m_help[group];
-
- options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
- value->has_default(), value->get_default_value(),
- value->has_implicit(), value->get_implicit_value(),
- std::move(arg_help),
- value->is_container(),
- value->is_boolean()});
}
- inline
- void
- Options::add_one_option
- (
- const std::string& option,
- std::shared_ptr<OptionDetails> details
- )
+ if (consume_remaining)
{
- auto in = m_options->emplace(option, details);
-
- if (!in.second)
+ while (current < argc)
{
- throw_or_mimic<option_exists_error>(option);
+ if (!consume_positional(argv[current]))
+ {
+ break;
+ }
+ ++current;
}
- }
- inline
- String
- Options::help_one_group(const std::string& g) const
- {
- typedef std::vector<std::pair<String, String>> OptionHelp;
-
- auto group = m_help.find(g);
- if (group == m_help.end())
+ //adjust argv for any that couldn't be swallowed
+ while (current != argc)
{
- return "";
+ argv[nextKeep] = argv[current];
+ ++nextKeep;
+ ++current;
}
+ }
- OptionHelp format;
+ argc = nextKeep;
+}
- size_t longest = 0;
+inline void
+Options::add_option(
+ const std::string &group,
+ const Option &option)
+{
+ add_options(group, {option});
+}
- String result;
+inline void
+Options::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)
+{
+ auto stringDesc = toLocalString(std::move(desc));
+ auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);
- if (!g.empty())
- {
- result += toLocalString(" " + g + " options:\n");
- }
+ if (s.size() > 0)
+ {
+ add_one_option(s, option);
+ }
- for (const auto& o : group->second.options)
- {
- if (m_positional_set.find(o.l) != m_positional_set.end() &&
- !m_show_positional)
- {
- continue;
- }
+ if (l.size() > 0)
+ {
+ add_one_option(l, option);
+ }
- auto s = format_option(o);
- longest = (std::max)(longest, stringLength(s));
- format.push_back(std::make_pair(s, String()));
- }
+ //add the help details
+ auto &options = m_help[group];
- longest = (std::min)(longest, static_cast<size_t>(OPTION_LONGEST));
+ options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
+ value->has_default(), value->get_default_value(),
+ value->has_implicit(), value->get_implicit_value(),
+ std::move(arg_help),
+ value->is_container(),
+ value->is_boolean()});
+}
- //widest allowed description
- auto allowed = size_t{76} - longest - OPTION_DESC_GAP;
+inline void
+Options::add_one_option(
+ const std::string &option,
+ std::shared_ptr<OptionDetails> details)
+{
+ auto in = m_options->emplace(option, details);
- auto fiter = format.begin();
- for (const auto& o : group->second.options)
- {
- if (m_positional_set.find(o.l) != m_positional_set.end() &&
- !m_show_positional)
- {
- continue;
- }
+ if (!in.second)
+ {
+ throw_or_mimic<option_exists_error>(option);
+ }
+}
- auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
+inline String
+Options::help_one_group(const std::string &g) const
+{
+ typedef std::vector<std::pair<String, String>> OptionHelp;
- result += fiter->first;
- if (stringLength(fiter->first) > longest)
- {
- result += '\n';
- result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
- }
- else
- {
- result += toLocalString(std::string(longest + OPTION_DESC_GAP -
- stringLength(fiter->first),
- ' '));
- }
- result += d;
- result += '\n';
+ auto group = m_help.find(g);
+ if (group == m_help.end())
+ {
+ return "";
+ }
- ++fiter;
- }
+ OptionHelp format;
- return result;
- }
+ size_t longest = 0;
- inline
- void
- Options::generate_group_help
- (
- String& result,
- const std::vector<std::string>& print_groups
- ) const
+ String result;
+
+ if (!g.empty())
{
- for (size_t i = 0; i != print_groups.size(); ++i)
- {
- const String& group_help_text = help_one_group(print_groups[i]);
- if (empty(group_help_text))
- {
- continue;
- }
- result += group_help_text;
- if (i < print_groups.size() - 1)
- {
- result += '\n';
- }
- }
+ result += toLocalString(" " + g + " options:\n");
}
- inline
- void
- Options::generate_all_groups_help(String& result) const
+ for (const auto &o : group->second.options)
{
- std::vector<std::string> all_groups;
- all_groups.reserve(m_help.size());
-
- for (auto& group : m_help)
+ if (m_positional_set.find(o.l) != m_positional_set.end() &&
+ !m_show_positional)
{
- all_groups.push_back(group.first);
+ continue;
}
- generate_group_help(result, all_groups);
+ auto s = format_option(o);
+ longest = (std::max)(longest, stringLength(s));
+ format.push_back(std::make_pair(s, String()));
}
- inline
- std::string
- Options::help(const std::vector<std::string>& help_groups) const
- {
- String result = m_help_string + "\nUsage:\n " +
- toLocalString(m_program) + " " + toLocalString(m_custom_help);
+ longest = (std::min)(longest, static_cast<size_t>(OPTION_LONGEST));
- if (m_positional.size() > 0 && m_positional_help.size() > 0) {
- result += " " + toLocalString(m_positional_help);
+ //widest allowed description
+ auto allowed = size_t{76} - longest - OPTION_DESC_GAP;
+
+ auto fiter = format.begin();
+ for (const auto &o : group->second.options)
+ {
+ if (m_positional_set.find(o.l) != m_positional_set.end() &&
+ !m_show_positional)
+ {
+ continue;
}
- result += "\n\n";
+ auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
- if (help_groups.size() == 0)
+ result += fiter->first;
+ if (stringLength(fiter->first) > longest)
{
- generate_all_groups_help(result);
+ result += '\n';
+ result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
}
else
{
- generate_group_help(result, help_groups);
+ result += toLocalString(std::string(longest + OPTION_DESC_GAP -
+ stringLength(fiter->first),
+ ' '));
}
+ result += d;
+ result += '\n';
- return toUTF8String(result);
+ ++fiter;
}
- inline
- const std::vector<std::string>
- Options::groups() const
+ return result;
+}
+
+inline void
+Options::generate_group_help(
+ String &result,
+ const std::vector<std::string> &print_groups) const
+{
+ for (size_t i = 0; i != print_groups.size(); ++i)
{
- std::vector<std::string> g;
+ const String &group_help_text = help_one_group(print_groups[i]);
+ if (empty(group_help_text))
+ {
+ continue;
+ }
+ result += group_help_text;
+ if (i < print_groups.size() - 1)
+ {
+ result += '\n';
+ }
+ }
+}
- std::transform(
- m_help.begin(),
- m_help.end(),
- std::back_inserter(g),
- [] (const std::map<std::string, HelpGroupDetails>::value_type& pair)
- {
- return pair.first;
- }
- );
+inline void
+Options::generate_all_groups_help(String &result) const
+{
+ std::vector<std::string> all_groups;
+ all_groups.reserve(m_help.size());
- return g;
+ for (auto &group : m_help)
+ {
+ all_groups.push_back(group.first);
}
- inline
- const HelpGroupDetails&
- Options::group_help(const std::string& group) const
+ generate_group_help(result, all_groups);
+}
+
+inline std::string
+Options::help(const std::vector<std::string> &help_groups) const
+{
+ String result = m_help_string + "\nUsage:\n " +
+ toLocalString(m_program) + " " + toLocalString(m_custom_help);
+
+ if (m_positional.size() > 0 && m_positional_help.size() > 0)
{
- return m_help.at(group);
+ result += " " + toLocalString(m_positional_help);
}
+ result += "\n\n";
+
+ if (help_groups.size() == 0)
+ {
+ generate_all_groups_help(result);
+ }
+ else
+ {
+ generate_group_help(result, help_groups);
+ }
+
+ return toUTF8String(result);
+}
+
+inline const std::vector<std::string>
+Options::groups() const
+{
+ std::vector<std::string> g;
+
+ std::transform(
+ m_help.begin(),
+ m_help.end(),
+ std::back_inserter(g),
+ [](const std::map<std::string, HelpGroupDetails>::value_type &pair) {
+ return pair.first;
+ });
+
+ return g;
}
+inline const HelpGroupDetails &
+Options::group_help(const std::string &group) const
+{
+ return m_help.at(group);
+}
+
+} // namespace cxxopts
+
#endif //CXXOPTS_HPP_INCLUDED \ No newline at end of file