Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-11-19 23:20:31

0001 /*
0002 
0003 Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck
0004 
0005 Permission is hereby granted, free of charge, to any person obtaining a copy
0006 of this software and associated documentation files (the "Software"), to deal
0007 in the Software without restriction, including without limitation the rights
0008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0009 copies of the Software, and to permit persons to whom the Software is
0010 furnished to do so, subject to the following conditions:
0011 
0012 The above copyright notice and this permission notice shall be included in
0013 all copies or substantial portions of the Software.
0014 
0015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
0021 THE SOFTWARE.
0022 
0023 */
0024 
0025 #ifndef CXXOPTS_HPP_INCLUDED
0026 #define CXXOPTS_HPP_INCLUDED
0027 
0028 #include <cstring>
0029 #include <cctype>
0030 #include <exception>
0031 #include <iostream>
0032 #include <map>
0033 #include <memory>
0034 #include <regex>
0035 #include <sstream>
0036 #include <string>
0037 #include <unordered_map>
0038 #include <unordered_set>
0039 #include <vector>
0040 #include <limits>
0041 
0042 #ifdef __cpp_lib_optional
0043 #include <optional>
0044 #define CXXOPTS_HAS_OPTIONAL
0045 #endif
0046 
0047 #define CXXOPTS__VERSION_MAJOR 2
0048 #define CXXOPTS__VERSION_MINOR 2
0049 #define CXXOPTS__VERSION_PATCH 0
0050 
0051 namespace cxxopts {
0052   static constexpr struct {
0053     uint8_t major, minor, patch;
0054   } version = {CXXOPTS__VERSION_MAJOR, CXXOPTS__VERSION_MINOR, CXXOPTS__VERSION_PATCH};
0055 }  // namespace cxxopts
0056 
0057 //when we ask cxxopts to use Unicode, help strings are processed using ICU,
0058 //which results in the correct lengths being computed for strings when they
0059 //are formatted for the help output
0060 //it is necessary to make sure that <unicode/unistr.h> can be found by the
0061 //compiler, and that icu-uc is linked in to the binary.
0062 
0063 #ifdef CXXOPTS_USE_UNICODE
0064 #include <unicode/unistr.h>
0065 
0066 namespace cxxopts {
0067   typedef icu::UnicodeString String;
0068 
0069   inline String toLocalString(std::string s) { return icu::UnicodeString::fromUTF8(std::move(s)); }
0070 
0071   class UnicodeStringIterator : public std::iterator<std::forward_iterator_tag, int32_t> {
0072   public:
0073     UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos) : s(string), i(pos) {}
0074 
0075     value_type operator*() const { return s->char32At(i); }
0076 
0077     bool operator==(const UnicodeStringIterator& rhs) const { return s == rhs.s && i == rhs.i; }
0078 
0079     bool operator!=(const UnicodeStringIterator& rhs) const { return !(*this == rhs); }
0080 
0081     UnicodeStringIterator& operator++() {
0082       ++i;
0083       return *this;
0084     }
0085 
0086     UnicodeStringIterator operator+(int32_t v) { return UnicodeStringIterator(s, i + v); }
0087 
0088   private:
0089     const icu::UnicodeString* s;
0090     int32_t i;
0091   };
0092 
0093   inline String& stringAppend(String& s, String a) { return s.append(std::move(a)); }
0094 
0095   inline String& stringAppend(String& s, int n, UChar32 c) {
0096     for (int i = 0; i != n; ++i) {
0097       s.append(c);
0098     }
0099 
0100     return s;
0101   }
0102 
0103   template <typename Iterator>
0104   String& stringAppend(String& s, Iterator begin, Iterator end) {
0105     while (begin != end) {
0106       s.append(*begin);
0107       ++begin;
0108     }
0109 
0110     return s;
0111   }
0112 
0113   inline size_t stringLength(const String& s) { return s.length(); }
0114 
0115   inline std::string toUTF8String(const String& s) {
0116     std::string result;
0117     s.toUTF8String(result);
0118 
0119     return result;
0120   }
0121 
0122   inline bool empty(const String& s) { return s.isEmpty(); }
0123 }  // namespace cxxopts
0124 
0125 namespace std {
0126   inline cxxopts::UnicodeStringIterator begin(const icu::UnicodeString& s) {
0127     return cxxopts::UnicodeStringIterator(&s, 0);
0128   }
0129 
0130   inline cxxopts::UnicodeStringIterator end(const icu::UnicodeString& s) {
0131     return cxxopts::UnicodeStringIterator(&s, s.length());
0132   }
0133 }  // namespace std
0134 
0135 //ifdef CXXOPTS_USE_UNICODE
0136 #else
0137 
0138 namespace cxxopts {
0139   typedef std::string String;
0140 
0141   template <typename T>
0142   T toLocalString(T&& t) {
0143     return std::forward<T>(t);
0144   }
0145 
0146   inline size_t stringLength(const String& s) { return s.length(); }
0147 
0148   inline String& stringAppend(String& s, String a) { return s.append(std::move(a)); }
0149 
0150   inline String& stringAppend(String& s, size_t n, char c) { return s.append(n, c); }
0151 
0152   template <typename Iterator>
0153   String& stringAppend(String& s, Iterator begin, Iterator end) {
0154     return s.append(begin, end);
0155   }
0156 
0157   template <typename T>
0158   std::string toUTF8String(T&& t) {
0159     return std::forward<T>(t);
0160   }
0161 
0162   inline bool empty(const std::string& s) { return s.empty(); }
0163 }  // namespace cxxopts
0164 
0165 //ifdef CXXOPTS_USE_UNICODE
0166 #endif
0167 
0168 namespace cxxopts {
0169   namespace {
0170 #ifdef _WIN32
0171     const std::string LQUOTE("\'");
0172     const std::string RQUOTE("\'");
0173 #else
0174     const std::string LQUOTE("‘");
0175     const std::string RQUOTE("’");
0176 #endif
0177   }  // namespace
0178 
0179   class Value : public std::enable_shared_from_this<Value> {
0180   public:
0181     virtual ~Value() = default;
0182 
0183     virtual std::shared_ptr<Value> clone() const = 0;
0184 
0185     virtual void parse(const std::string& text) const = 0;
0186 
0187     virtual void parse() const = 0;
0188 
0189     virtual bool has_default() const = 0;
0190 
0191     virtual bool is_container() const = 0;
0192 
0193     virtual bool has_implicit() const = 0;
0194 
0195     virtual std::string get_default_value() const = 0;
0196 
0197     virtual std::string get_implicit_value() const = 0;
0198 
0199     virtual std::shared_ptr<Value> default_value(const std::string& value) = 0;
0200 
0201     virtual std::shared_ptr<Value> implicit_value(const std::string& value) = 0;
0202 
0203     virtual bool is_boolean() const = 0;
0204   };
0205 
0206   class OptionException : public std::exception {
0207   public:
0208     OptionException(const std::string& message) : m_message(message) {}
0209 
0210     virtual const char* what() const noexcept { return m_message.c_str(); }
0211 
0212   private:
0213     std::string m_message;
0214   };
0215 
0216   class OptionSpecException : public OptionException {
0217   public:
0218     OptionSpecException(const std::string& message) : OptionException(message) {}
0219   };
0220 
0221   class OptionParseException : public OptionException {
0222   public:
0223     OptionParseException(const std::string& message) : OptionException(message) {}
0224   };
0225 
0226   class Option_exists_error : public OptionSpecException {
0227   public:
0228     Option_exists_error(const std::string& option)
0229         : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists") {}
0230   };
0231 
0232   class Invalid_option_format_error : public OptionSpecException {
0233   public:
0234     Invalid_option_format_error(const std::string& format)
0235         : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE) {}
0236   };
0237 
0238   class Option_syntax_exception : public OptionParseException {
0239   public:
0240     Option_syntax_exception(const std::string& text)
0241         : OptionParseException("Argument " + LQUOTE + text + RQUOTE + " starts with a - but has incorrect syntax") {}
0242   };
0243 
0244   class Option_not_exists_exception : public OptionParseException {
0245   public:
0246     Option_not_exists_exception(const std::string& option)
0247         : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist") {}
0248   };
0249 
0250   class Missing_argument_exception : public OptionParseException {
0251   public:
0252     Missing_argument_exception(const std::string& option)
0253         : OptionParseException("Option " + LQUOTE + option + RQUOTE + " is missing an argument") {}
0254   };
0255 
0256   class Option_requires_argument_exception : public OptionParseException {
0257   public:
0258     Option_requires_argument_exception(const std::string& option)
0259         : OptionParseException("Option " + LQUOTE + option + RQUOTE + " requires an argument") {}
0260   };
0261 
0262   class Option_not_has_argument_exception : public OptionParseException {
0263   public:
0264     Option_not_has_argument_exception(const std::string& option, const std::string& arg)
0265         : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not take an argument, but argument " +
0266                                LQUOTE + arg + RQUOTE + " given") {}
0267   };
0268 
0269   class Option_not_present_exception : public OptionParseException {
0270   public:
0271     Option_not_present_exception(const std::string& option)
0272         : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present") {}
0273   };
0274 
0275   class Argument_incorrect_type : public OptionParseException {
0276   public:
0277     Argument_incorrect_type(const std::string& arg)
0278         : OptionParseException("Argument " + LQUOTE + arg + RQUOTE + " failed to parse") {}
0279   };
0280 
0281   class Option_required_exception : public OptionParseException {
0282   public:
0283     Option_required_exception(const std::string& option)
0284         : OptionParseException("Option " + LQUOTE + option + RQUOTE + " is required but not present") {}
0285   };
0286 
0287   namespace values {
0288     namespace {
0289       std::basic_regex<char> integer_pattern("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
0290       std::basic_regex<char> truthy_pattern("(t|T)(rue)?");
0291       std::basic_regex<char> falsy_pattern("((f|F)(alse)?)?");
0292     }  // namespace
0293 
0294     namespace detail {
0295       template <typename T, bool B>
0296       struct SignedCheck;
0297 
0298       template <typename T>
0299       struct SignedCheck<T, true> {
0300         template <typename U>
0301         void operator()(bool negative, U u, const std::string& text) {
0302           if (negative) {
0303             if (u > static_cast<U>(-(std::numeric_limits<T>::min)())) {
0304               throw Argument_incorrect_type(text);
0305             }
0306           } else {
0307             if (u > static_cast<U>((std::numeric_limits<T>::max)())) {
0308               throw Argument_incorrect_type(text);
0309             }
0310           }
0311         }
0312       };
0313 
0314       template <typename T>
0315       struct SignedCheck<T, false> {
0316         template <typename U>
0317         void operator()(bool, U, const std::string&) {}
0318       };
0319 
0320       template <typename T, typename U>
0321       void check_signed_range(bool negative, U value, const std::string& text) {
0322         SignedCheck<T, std::numeric_limits<T>::is_signed>()(negative, value, text);
0323       }
0324     }  // namespace detail
0325 
0326     template <typename R, typename T>
0327     R checked_negate(T&& t, const std::string&, std::true_type) {
0328       // if we got to here, then `t` is a positive number that fits into
0329       // `R`. So to avoid MSVC C4146, we first cast it to `R`.
0330       // See https://github.com/jarro2783/cxxopts/issues/62 for more details.
0331       return -static_cast<R>(t);
0332     }
0333 
0334     template <typename R, typename T>
0335     T checked_negate(T&&, const std::string& text, std::false_type) {
0336       throw Argument_incorrect_type(text);
0337     }
0338 
0339     template <typename T>
0340     void integer_parser(const std::string& text, T& value) {
0341       std::smatch match;
0342       std::regex_match(text, match, integer_pattern);
0343 
0344       if (match.length() == 0) {
0345         throw Argument_incorrect_type(text);
0346       }
0347 
0348       if (match.length(4) > 0) {
0349         value = 0;
0350         return;
0351       }
0352 
0353       using US = typename std::make_unsigned<T>::type;
0354 
0355       constexpr auto umax = (std::numeric_limits<US>::max)();
0356       constexpr bool is_signed = std::numeric_limits<T>::is_signed;
0357       const bool negative = match.length(1) > 0;
0358       const uint8_t base = match.length(2) > 0 ? 16 : 10;
0359 
0360       auto value_match = match[3];
0361 
0362       US result = 0;
0363 
0364       for (auto iter = value_match.first; iter != value_match.second; ++iter) {
0365         US digit = 0;
0366 
0367         if (*iter >= '0' && *iter <= '9') {
0368           digit = *iter - '0';
0369         } else if (base == 16 && *iter >= 'a' && *iter <= 'f') {
0370           digit = *iter - 'a' + 10;
0371         } else if (base == 16 && *iter >= 'A' && *iter <= 'F') {
0372           digit = *iter - 'A' + 10;
0373         } else {
0374           throw Argument_incorrect_type(text);
0375         }
0376 
0377         if (umax - digit < result * base) {
0378           throw Argument_incorrect_type(text);
0379         }
0380 
0381         result = result * base + digit;
0382       }
0383 
0384       detail::check_signed_range<T>(negative, result, text);
0385 
0386       if (negative) {
0387         value = checked_negate<T>(result, text, std::integral_constant<bool, is_signed>());
0388       } else {
0389         value = result;
0390       }
0391     }
0392 
0393     template <typename T>
0394     void stringstream_parser(const std::string& text, T& value) {
0395       std::stringstream in(text);
0396       in >> value;
0397       if (!in) {
0398         throw Argument_incorrect_type(text);
0399       }
0400     }
0401 
0402     inline void parse_value(const std::string& text, uint8_t& value) { integer_parser(text, value); }
0403 
0404     inline void parse_value(const std::string& text, int8_t& value) { integer_parser(text, value); }
0405 
0406     inline void parse_value(const std::string& text, uint16_t& value) { integer_parser(text, value); }
0407 
0408     inline void parse_value(const std::string& text, int16_t& value) { integer_parser(text, value); }
0409 
0410     inline void parse_value(const std::string& text, uint32_t& value) { integer_parser(text, value); }
0411 
0412     inline void parse_value(const std::string& text, int32_t& value) { integer_parser(text, value); }
0413 
0414     inline void parse_value(const std::string& text, uint64_t& value) { integer_parser(text, value); }
0415 
0416     inline void parse_value(const std::string& text, int64_t& value) { integer_parser(text, value); }
0417 
0418     inline void parse_value(const std::string& text, bool& value) {
0419       std::smatch result;
0420       std::regex_match(text, result, truthy_pattern);
0421 
0422       if (!result.empty()) {
0423         value = true;
0424         return;
0425       }
0426 
0427       std::regex_match(text, result, falsy_pattern);
0428       if (!result.empty()) {
0429         value = false;
0430         return;
0431       }
0432 
0433       throw Argument_incorrect_type(text);
0434     }
0435 
0436     inline void parse_value(const std::string& text, std::string& value) { value = text; }
0437 
0438     // The fallback parser. It uses the stringstream parser to parse all types
0439     // that have not been overloaded explicitly.  It has to be placed in the
0440     // source code before all other more specialized templates.
0441     template <typename T>
0442     void parse_value(const std::string& text, T& value) {
0443       stringstream_parser(text, value);
0444     }
0445 
0446     template <typename T>
0447     void parse_value(const std::string& text, std::vector<T>& value) {
0448       T v;
0449       parse_value(text, v);
0450       value.push_back(v);
0451     }
0452 
0453 #ifdef CXXOPTS_HAS_OPTIONAL
0454     template <typename T>
0455     void parse_value(const std::string& text, std::optional<T>& value) {
0456       T result;
0457       parse_value(text, result);
0458       value = std::move(result);
0459     }
0460 #endif
0461 
0462     template <typename T>
0463     struct Type_is_container {
0464       static constexpr bool value = false;
0465     };
0466 
0467     template <typename T>
0468     struct Type_is_container<std::vector<T>> {
0469       static constexpr bool value = true;
0470     };
0471 
0472     template <typename T>
0473     class Abstract_value : public Value {
0474       using Self = Abstract_value<T>;
0475 
0476     public:
0477       Abstract_value() : m_result(std::make_shared<T>()), m_store(m_result.get()) {}
0478 
0479       Abstract_value(T* t) : m_store(t) {}
0480 
0481       virtual ~Abstract_value() = default;
0482 
0483       Abstract_value(const Abstract_value& rhs) {
0484         if (rhs.m_result) {
0485           m_result = std::make_shared<T>();
0486           m_store = m_result.get();
0487         } else {
0488           m_store = rhs.m_store;
0489         }
0490 
0491         m_default = rhs.m_default;
0492         m_implicit = rhs.m_implicit;
0493         m_default_value = rhs.m_default_value;
0494         m_implicit_value = rhs.m_implicit_value;
0495       }
0496 
0497       void parse(const std::string& text) const { parse_value(text, *m_store); }
0498 
0499       bool is_container() const { return Type_is_container<T>::value; }
0500 
0501       void parse() const { parse_value(m_default_value, *m_store); }
0502 
0503       bool has_default() const { return m_default; }
0504 
0505       bool has_implicit() const { return m_implicit; }
0506 
0507       std::shared_ptr<Value> default_value(const std::string& value) {
0508         m_default = true;
0509         m_default_value = value;
0510         return shared_from_this();
0511       }
0512 
0513       std::shared_ptr<Value> implicit_value(const std::string& value) {
0514         m_implicit = true;
0515         m_implicit_value = value;
0516         return shared_from_this();
0517       }
0518 
0519       std::string get_default_value() const { return m_default_value; }
0520 
0521       std::string get_implicit_value() const { return m_implicit_value; }
0522 
0523       bool is_boolean() const { return std::is_same<T, bool>::value; }
0524 
0525       const T& get() const {
0526         if (m_store == nullptr) {
0527           return *m_result;
0528         } else {
0529           return *m_store;
0530         }
0531       }
0532 
0533     protected:
0534       std::shared_ptr<T> m_result;
0535       T* m_store;
0536 
0537       bool m_default = false;
0538       bool m_implicit = false;
0539 
0540       std::string m_default_value;
0541       std::string m_implicit_value;
0542     };
0543 
0544     template <typename T>
0545     class Standard_value : public Abstract_value<T> {
0546     public:
0547       using Abstract_value<T>::Abstract_value;
0548 
0549       std::shared_ptr<Value> clone() const { return std::make_shared<Standard_value<T>>(*this); }
0550     };
0551 
0552     template <>
0553     class Standard_value<bool> : public Abstract_value<bool> {
0554     public:
0555       ~Standard_value() = default;
0556 
0557       Standard_value() { set_default_and_implicit(); }
0558 
0559       Standard_value(bool* b) : Abstract_value(b) { set_default_and_implicit(); }
0560 
0561       std::shared_ptr<Value> clone() const { return std::make_shared<Standard_value<bool>>(*this); }
0562 
0563     private:
0564       void set_default_and_implicit() {
0565         m_default = true;
0566         m_default_value = "false";
0567         m_implicit = true;
0568         m_implicit_value = "true";
0569       }
0570     };
0571   }  // namespace values
0572 
0573   template <typename T>
0574   std::shared_ptr<Value> value() {
0575     return std::make_shared<values::Standard_value<T>>();
0576   }
0577 
0578   template <typename T>
0579   std::shared_ptr<Value> value(T& t) {
0580     return std::make_shared<values::Standard_value<T>>(&t);
0581   }
0582 
0583   class OptionAdder;
0584 
0585   class OptionDetails {
0586   public:
0587     OptionDetails(const std::string& short_,
0588                   const std::string& long_,
0589                   const String& desc,
0590                   std::shared_ptr<const Value> val)
0591         : m_short(short_), m_long(long_), m_desc(desc), m_value(val), m_count(0) {}
0592 
0593     OptionDetails(const OptionDetails& rhs) : m_desc(rhs.m_desc), m_count(rhs.m_count) {
0594       m_value = rhs.m_value->clone();
0595     }
0596 
0597     OptionDetails(OptionDetails&& rhs) = default;
0598 
0599     const String& description() const { return m_desc; }
0600 
0601     const Value& value() const { return *m_value; }
0602 
0603     std::shared_ptr<Value> make_storage() const { return m_value->clone(); }
0604 
0605     const std::string& short_name() const { return m_short; }
0606 
0607     const std::string& long_name() const { return m_long; }
0608 
0609   private:
0610     std::string m_short;
0611     std::string m_long;
0612     String m_desc;
0613     std::shared_ptr<const Value> m_value;
0614     int m_count;
0615   };
0616 
0617   struct HelpOptionDetails {
0618     std::string s;
0619     std::string l;
0620     String desc;
0621     bool has_default;
0622     std::string default_value;
0623     bool has_implicit;
0624     std::string implicit_value;
0625     std::string arg_help;
0626     bool is_container;
0627     bool is_boolean;
0628   };
0629 
0630   struct HelpGroupDetails {
0631     std::string name;
0632     std::string description;
0633     std::vector<HelpOptionDetails> options;
0634   };
0635 
0636   class OptionValue {
0637   public:
0638     void parse(std::shared_ptr<const OptionDetails> details, const std::string& text) {
0639       ensure_value(details);
0640       ++m_count;
0641       m_value->parse(text);
0642     }
0643 
0644     void parse_default(std::shared_ptr<const OptionDetails> details) {
0645       ensure_value(details);
0646       m_value->parse();
0647     }
0648 
0649     size_t count() const { return m_count; }
0650 
0651     template <typename T>
0652     const T& as() const {
0653       if (m_value == nullptr) {
0654         throw std::domain_error("No value");
0655       }
0656 
0657 #ifdef CXXOPTS_NO_RTTI
0658       return static_cast<const values::Standard_value<T>&>(*m_value).get();
0659 #else
0660       return dynamic_cast<const values::Standard_value<T>&>(*m_value).get();
0661 #endif
0662     }
0663 
0664   private:
0665     void ensure_value(std::shared_ptr<const OptionDetails> details) {
0666       if (m_value == nullptr) {
0667         m_value = details->make_storage();
0668       }
0669     }
0670 
0671     std::shared_ptr<Value> m_value;
0672     size_t m_count = 0;
0673   };
0674 
0675   class KeyValue {
0676   public:
0677     KeyValue(std::string key_, std::string value_) : m_key(std::move(key_)), m_value(std::move(value_)) {}
0678 
0679     const std::string& key() const { return m_key; }
0680 
0681     const std::string& value() const { return m_value; }
0682 
0683     template <typename T>
0684     T as() const {
0685       T result;
0686       values::parse_value(m_value, result);
0687       return result;
0688     }
0689 
0690   private:
0691     std::string m_key;
0692     std::string m_value;
0693   };
0694 
0695   class ParseResult {
0696   public:
0697     ParseResult(const std::shared_ptr<std::unordered_map<std::string, std::shared_ptr<OptionDetails>>>,
0698                 std::vector<std::string>,
0699                 bool allow_unrecognised,
0700                 int&,
0701                 char**&);
0702 
0703     size_t count(const std::string& o) const {
0704       auto iter = m_options->find(o);
0705       if (iter == m_options->end()) {
0706         return 0;
0707       }
0708 
0709       auto riter = m_results.find(iter->second);
0710 
0711       return riter->second.count();
0712     }
0713 
0714     const OptionValue& operator[](const std::string& option) const {
0715       auto iter = m_options->find(option);
0716 
0717       if (iter == m_options->end()) {
0718         throw Option_not_present_exception(option);
0719       }
0720 
0721       auto riter = m_results.find(iter->second);
0722 
0723       return riter->second;
0724     }
0725 
0726     const std::vector<KeyValue>& arguments() const { return m_sequential; }
0727 
0728   private:
0729     void parse(int& argc, char**& argv);
0730 
0731     void add_to_option(const std::string& option, const std::string& arg);
0732 
0733     bool consume_positional(std::string a);
0734 
0735     void parse_option(std::shared_ptr<OptionDetails> value, const std::string& name, const std::string& arg = "");
0736 
0737     void parse_default(std::shared_ptr<OptionDetails> details);
0738 
0739     void checked_parse_arg(
0740         int argc, char* argv[], int& current, std::shared_ptr<OptionDetails> value, const std::string& name);
0741 
0742     const std::shared_ptr<std::unordered_map<std::string, std::shared_ptr<OptionDetails>>> m_options;
0743     std::vector<std::string> m_positional;
0744     std::vector<std::string>::iterator m_next_positional;
0745     std::unordered_set<std::string> m_positional_set;
0746     std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results;
0747 
0748     bool m_allow_unrecognised;
0749 
0750     std::vector<KeyValue> m_sequential;
0751   };
0752 
0753   class Options {
0754     typedef std::unordered_map<std::string, std::shared_ptr<OptionDetails>> OptionMap;
0755 
0756   public:
0757     Options(std::string program, std::string help_string = "")
0758         : m_program(std::move(program)),
0759           m_help_string(toLocalString(std::move(help_string))),
0760           m_custom_help("[OPTION...]"),
0761           m_positional_help("positional parameters"),
0762           m_show_positional(false),
0763           m_allow_unrecognised(false),
0764           m_options(std::make_shared<OptionMap>()),
0765           m_next_positional(m_positional.end()) {}
0766 
0767     Options& positional_help(std::string help_text) {
0768       m_positional_help = std::move(help_text);
0769       return *this;
0770     }
0771 
0772     Options& custom_help(std::string help_text) {
0773       m_custom_help = std::move(help_text);
0774       return *this;
0775     }
0776 
0777     Options& show_positional_help() {
0778       m_show_positional = true;
0779       return *this;
0780     }
0781 
0782     Options& allow_unrecognised_options() {
0783       m_allow_unrecognised = true;
0784       return *this;
0785     }
0786 
0787     ParseResult parse(int& argc, char**& argv);
0788 
0789     OptionAdder add_options(std::string group = "");
0790 
0791     void add_option(const std::string& group,
0792                     const std::string& s,
0793                     const std::string& l,
0794                     std::string desc,
0795                     std::shared_ptr<const Value> value,
0796                     std::string arg_help);
0797 
0798     //parse positional arguments into the given option
0799     void parse_positional(std::string option);
0800 
0801     void parse_positional(std::vector<std::string> options);
0802 
0803     void parse_positional(std::initializer_list<std::string> options);
0804 
0805     template <typename Iterator>
0806     void parse_positional(Iterator begin, Iterator end) {
0807       parse_positional(std::vector<std::string>{begin, end});
0808     }
0809 
0810     std::string help(const std::vector<std::string>& groups = {}) const;
0811 
0812     const std::vector<std::string> groups() const;
0813 
0814     const HelpGroupDetails& group_help(const std::string& group) const;
0815 
0816   private:
0817     void add_one_option(const std::string& option, std::shared_ptr<OptionDetails> details);
0818 
0819     String help_one_group(const std::string& group) const;
0820 
0821     void generate_group_help(String& result, const std::vector<std::string>& groups) const;
0822 
0823     void generate_all_groups_help(String& result) const;
0824 
0825     std::string m_program;
0826     String m_help_string;
0827     std::string m_custom_help;
0828     std::string m_positional_help;
0829     bool m_show_positional;
0830     bool m_allow_unrecognised;
0831 
0832     std::shared_ptr<OptionMap> m_options;
0833     std::vector<std::string> m_positional;
0834     std::vector<std::string>::iterator m_next_positional;
0835     std::unordered_set<std::string> m_positional_set;
0836 
0837     //mapping from groups to help options
0838     std::map<std::string, HelpGroupDetails> m_help;
0839   };
0840 
0841   class OptionAdder {
0842   public:
0843     OptionAdder(Options& options, std::string group) : m_options(options), m_group(std::move(group)) {}
0844 
0845     OptionAdder& operator()(const std::string& opts,
0846                             const std::string& desc,
0847                             std::shared_ptr<const Value> value = ::cxxopts::value<bool>(),
0848                             std::string arg_help = "");
0849 
0850   private:
0851     Options& m_options;
0852     std::string m_group;
0853   };
0854 
0855   namespace {
0856     constexpr int OPTION_LONGEST = 30;
0857     constexpr int OPTION_DESC_GAP = 2;
0858 
0859     std::basic_regex<char> option_matcher("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
0860 
0861     std::basic_regex<char> option_specifier("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
0862 
0863     String format_option(const HelpOptionDetails& o) {
0864       auto& s = o.s;
0865       auto& l = o.l;
0866 
0867       String result = "  ";
0868 
0869       if (s.size() > 0) {
0870         result += "-" + toLocalString(s) + ",";
0871       } else {
0872         result += "   ";
0873       }
0874 
0875       if (l.size() > 0) {
0876         result += " --" + toLocalString(l);
0877       }
0878 
0879       auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg";
0880 
0881       if (!o.is_boolean) {
0882         if (o.has_implicit) {
0883           result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
0884         } else {
0885           result += " " + arg;
0886         }
0887       }
0888 
0889       return result;
0890     }
0891 
0892     String format_description(const HelpOptionDetails& o, size_t start, size_t width) {
0893       auto desc = o.desc;
0894 
0895       if (o.has_default && (!o.is_boolean || o.default_value != "false")) {
0896         desc += toLocalString(" (default: " + o.default_value + ")");
0897       }
0898 
0899       String result;
0900 
0901       auto current = std::begin(desc);
0902       auto startLine = current;
0903       auto lastSpace = current;
0904 
0905       auto size = size_t{};
0906 
0907       while (current != std::end(desc)) {
0908         if (*current == ' ') {
0909           lastSpace = current;
0910         }
0911 
0912         if (*current == '\n') {
0913           startLine = current + 1;
0914           lastSpace = startLine;
0915         } else if (size > width) {
0916           if (lastSpace == startLine) {
0917             stringAppend(result, startLine, current + 1);
0918             stringAppend(result, "\n");
0919             stringAppend(result, start, ' ');
0920             startLine = current + 1;
0921             lastSpace = startLine;
0922           } else {
0923             stringAppend(result, startLine, lastSpace);
0924             stringAppend(result, "\n");
0925             stringAppend(result, start, ' ');
0926             startLine = lastSpace + 1;
0927           }
0928           size = 0;
0929         } else {
0930           ++size;
0931         }
0932 
0933         ++current;
0934       }
0935 
0936       //append whatever is left
0937       stringAppend(result, startLine, current);
0938 
0939       return result;
0940     }
0941   }  // namespace
0942 
0943   inline ParseResult::ParseResult(
0944       const std::shared_ptr<std::unordered_map<std::string, std::shared_ptr<OptionDetails>>> options,
0945       std::vector<std::string> positional,
0946       bool allow_unrecognised,
0947       int& argc,
0948       char**& argv)
0949       : m_options(options),
0950         m_positional(std::move(positional)),
0951         m_next_positional(m_positional.begin()),
0952         m_allow_unrecognised(allow_unrecognised) {
0953     parse(argc, argv);
0954   }
0955 
0956   inline OptionAdder Options::add_options(std::string group) { return OptionAdder(*this, std::move(group)); }
0957 
0958   inline OptionAdder& OptionAdder::operator()(const std::string& opts,
0959                                               const std::string& desc,
0960                                               std::shared_ptr<const Value> value,
0961                                               std::string arg_help) {
0962     std::match_results<const char*> result;
0963     std::regex_match(opts.c_str(), result, option_specifier);
0964 
0965     if (result.empty()) {
0966       throw Invalid_option_format_error(opts);
0967     }
0968 
0969     const auto& short_match = result[2];
0970     const auto& long_match = result[3];
0971 
0972     if (!short_match.length() && !long_match.length()) {
0973       throw Invalid_option_format_error(opts);
0974     } else if (long_match.length() == 1 && short_match.length()) {
0975       throw Invalid_option_format_error(opts);
0976     }
0977 
0978     auto option_names = [](const std::sub_match<const char*>& short_, const std::sub_match<const char*>& long_) {
0979       if (long_.length() == 1) {
0980         return std::make_tuple(long_.str(), short_.str());
0981       } else {
0982         return std::make_tuple(short_.str(), long_.str());
0983       }
0984     }(short_match, long_match);
0985 
0986     m_options.add_option(
0987         m_group, std::get<0>(option_names), std::get<1>(option_names), desc, value, std::move(arg_help));
0988 
0989     return *this;
0990   }
0991 
0992   inline void ParseResult::parse_default(std::shared_ptr<OptionDetails> details) {
0993     m_results[details].parse_default(details);
0994   }
0995 
0996   inline void ParseResult::parse_option(std::shared_ptr<OptionDetails> value,
0997                                         const std::string& /*name*/,
0998                                         const std::string& arg) {
0999     auto& result = m_results[value];
1000     result.parse(value, arg);
1001 
1002     m_sequential.emplace_back(value->long_name(), arg);
1003   }
1004 
1005   inline void ParseResult::checked_parse_arg(
1006       int argc, char* argv[], int& current, std::shared_ptr<OptionDetails> value, const std::string& name) {
1007     if (current + 1 >= argc) {
1008       if (value->value().has_implicit()) {
1009         parse_option(value, name, value->value().get_implicit_value());
1010       } else {
1011         throw Missing_argument_exception(name);
1012       }
1013     } else {
1014       if (value->value().has_implicit()) {
1015         parse_option(value, name, value->value().get_implicit_value());
1016       } else {
1017         parse_option(value, name, argv[current + 1]);
1018         ++current;
1019       }
1020     }
1021   }
1022 
1023   inline void ParseResult::add_to_option(const std::string& option, const std::string& arg) {
1024     auto iter = m_options->find(option);
1025 
1026     if (iter == m_options->end()) {
1027       throw Option_not_exists_exception(option);
1028     }
1029 
1030     parse_option(iter->second, option, arg);
1031   }
1032 
1033   inline bool ParseResult::consume_positional(std::string a) {
1034     while (m_next_positional != m_positional.end()) {
1035       auto iter = m_options->find(*m_next_positional);
1036       if (iter != m_options->end()) {
1037         auto& result = m_results[iter->second];
1038         if (!iter->second->value().is_container()) {
1039           if (result.count() == 0) {
1040             add_to_option(*m_next_positional, a);
1041             ++m_next_positional;
1042             return true;
1043           } else {
1044             ++m_next_positional;
1045             continue;
1046           }
1047         } else {
1048           add_to_option(*m_next_positional, a);
1049           return true;
1050         }
1051       }
1052       ++m_next_positional;
1053     }
1054 
1055     return false;
1056   }
1057 
1058   inline void Options::parse_positional(std::string option) {
1059     parse_positional(std::vector<std::string>{std::move(option)});
1060   }
1061 
1062   inline void Options::parse_positional(std::vector<std::string> options) {
1063     m_positional = std::move(options);
1064     m_next_positional = m_positional.begin();
1065 
1066     m_positional_set.insert(m_positional.begin(), m_positional.end());
1067   }
1068 
1069   inline void Options::parse_positional(std::initializer_list<std::string> options) {
1070     parse_positional(std::vector<std::string>(std::move(options)));
1071   }
1072 
1073   inline ParseResult Options::parse(int& argc, char**& argv) {
1074     ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv);
1075     return result;
1076   }
1077 
1078   inline void ParseResult::parse(int& argc, char**& argv) {
1079     int current = 1;
1080 
1081     int nextKeep = 1;
1082 
1083     bool consume_remaining = false;
1084 
1085     while (current != argc) {
1086       if (strcmp(argv[current], "--") == 0) {
1087         consume_remaining = true;
1088         ++current;
1089         break;
1090       }
1091 
1092       std::match_results<const char*> result;
1093       std::regex_match(argv[current], result, option_matcher);
1094 
1095       if (result.empty()) {
1096         //not a flag
1097 
1098         // but if it starts with a `-`, then it's an error
1099         if (argv[current][0] == '-' && argv[current][1] != '\0') {
1100           throw Option_syntax_exception(argv[current]);
1101         }
1102 
1103         //if true is returned here then it was consumed, otherwise it is
1104         //ignored
1105         if (consume_positional(argv[current])) {
1106         } else {
1107           argv[nextKeep] = argv[current];
1108           ++nextKeep;
1109         }
1110         //if we return from here then it was parsed successfully, so continue
1111       } else {
1112         //short or long option?
1113         if (result[4].length() != 0) {
1114           const std::string& s = result[4];
1115 
1116           for (std::size_t i = 0; i != s.size(); ++i) {
1117             std::string name(1, s[i]);
1118             auto iter = m_options->find(name);
1119 
1120             if (iter == m_options->end()) {
1121               if (m_allow_unrecognised) {
1122                 continue;
1123               } else {
1124                 //error
1125                 throw Option_not_exists_exception(name);
1126               }
1127             }
1128 
1129             auto value = iter->second;
1130 
1131             if (i + 1 == s.size()) {
1132               //it must be the last argument
1133               checked_parse_arg(argc, argv, current, value, name);
1134             } else if (value->value().has_implicit()) {
1135               parse_option(value, name, value->value().get_implicit_value());
1136             } else {
1137               //error
1138               throw Option_requires_argument_exception(name);
1139             }
1140           }
1141         } else if (result[1].length() != 0) {
1142           const std::string& name = result[1];
1143 
1144           auto iter = m_options->find(name);
1145 
1146           if (iter == m_options->end()) {
1147             if (m_allow_unrecognised) {
1148               // keep unrecognised options in argument list, skip to next argument
1149               argv[nextKeep] = argv[current];
1150               ++nextKeep;
1151               ++current;
1152               continue;
1153             } else {
1154               //error
1155               throw Option_not_exists_exception(name);
1156             }
1157           }
1158 
1159           auto opt = iter->second;
1160 
1161           //equals provided for long option?
1162           if (result[2].length() != 0) {
1163             //parse the option given
1164 
1165             parse_option(opt, name, result[3]);
1166           } else {
1167             //parse the next argument
1168             checked_parse_arg(argc, argv, current, opt, name);
1169           }
1170         }
1171       }
1172 
1173       ++current;
1174     }
1175 
1176     for (auto& opt : *m_options) {
1177       auto& detail = opt.second;
1178       auto& value = detail->value();
1179 
1180       auto& store = m_results[detail];
1181 
1182       if (!store.count() && value.has_default()) {
1183         parse_default(detail);
1184       }
1185     }
1186 
1187     if (consume_remaining) {
1188       while (current < argc) {
1189         if (!consume_positional(argv[current])) {
1190           break;
1191         }
1192         ++current;
1193       }
1194 
1195       //adjust argv for any that couldn't be swallowed
1196       while (current != argc) {
1197         argv[nextKeep] = argv[current];
1198         ++nextKeep;
1199         ++current;
1200       }
1201     }
1202 
1203     argc = nextKeep;
1204   }
1205 
1206   inline void Options::add_option(const std::string& group,
1207                                   const std::string& s,
1208                                   const std::string& l,
1209                                   std::string desc,
1210                                   std::shared_ptr<const Value> value,
1211                                   std::string arg_help) {
1212     auto stringDesc = toLocalString(std::move(desc));
1213     auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);
1214 
1215     if (s.size() > 0) {
1216       add_one_option(s, option);
1217     }
1218 
1219     if (l.size() > 0) {
1220       add_one_option(l, option);
1221     }
1222 
1223     //add the help details
1224     auto& options = m_help[group];
1225 
1226     options.options.emplace_back(HelpOptionDetails{s,
1227                                                    l,
1228                                                    stringDesc,
1229                                                    value->has_default(),
1230                                                    value->get_default_value(),
1231                                                    value->has_implicit(),
1232                                                    value->get_implicit_value(),
1233                                                    std::move(arg_help),
1234                                                    value->is_container(),
1235                                                    value->is_boolean()});
1236   }
1237 
1238   inline void Options::add_one_option(const std::string& option, std::shared_ptr<OptionDetails> details) {
1239     auto in = m_options->emplace(option, details);
1240 
1241     if (!in.second) {
1242       throw Option_exists_error(option);
1243     }
1244   }
1245 
1246   inline String Options::help_one_group(const std::string& g) const {
1247     typedef std::vector<std::pair<String, String>> OptionHelp;
1248 
1249     auto group = m_help.find(g);
1250     if (group == m_help.end()) {
1251       return "";
1252     }
1253 
1254     OptionHelp format;
1255 
1256     size_t longest = 0;
1257 
1258     String result;
1259 
1260     if (!g.empty()) {
1261       result += toLocalString(" " + g + " options:\n");
1262     }
1263 
1264     for (const auto& o : group->second.options) {
1265       if (o.is_container && m_positional_set.find(o.l) != m_positional_set.end() && !m_show_positional) {
1266         continue;
1267       }
1268 
1269       auto s = format_option(o);
1270       longest = (std::max)(longest, stringLength(s));
1271       format.push_back(std::make_pair(s, String()));
1272     }
1273 
1274     longest = (std::min)(longest, static_cast<size_t>(OPTION_LONGEST));
1275 
1276     //widest allowed description
1277     auto allowed = size_t{76} - longest - OPTION_DESC_GAP;
1278 
1279     auto fiter = format.begin();
1280     for (const auto& o : group->second.options) {
1281       if (o.is_container && m_positional_set.find(o.l) != m_positional_set.end() && !m_show_positional) {
1282         continue;
1283       }
1284 
1285       auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
1286 
1287       result += fiter->first;
1288       if (stringLength(fiter->first) > longest) {
1289         result += '\n';
1290         result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
1291       } else {
1292         result += toLocalString(std::string(longest + OPTION_DESC_GAP - stringLength(fiter->first), ' '));
1293       }
1294       result += d;
1295       result += '\n';
1296 
1297       ++fiter;
1298     }
1299 
1300     return result;
1301   }
1302 
1303   inline void Options::generate_group_help(String& result, const std::vector<std::string>& print_groups) const {
1304     for (size_t i = 0; i != print_groups.size(); ++i) {
1305       const String& group_help_text = help_one_group(print_groups[i]);
1306       if (empty(group_help_text)) {
1307         continue;
1308       }
1309       result += group_help_text;
1310       if (i < print_groups.size() - 1) {
1311         result += '\n';
1312       }
1313     }
1314   }
1315 
1316   inline void Options::generate_all_groups_help(String& result) const {
1317     std::vector<std::string> all_groups;
1318     all_groups.reserve(m_help.size());
1319 
1320     for (auto& group : m_help) {
1321       all_groups.push_back(group.first);
1322     }
1323 
1324     generate_group_help(result, all_groups);
1325   }
1326 
1327   inline std::string Options::help(const std::vector<std::string>& help_groups) const {
1328     String result = m_help_string + "\nUsage:\n  " + toLocalString(m_program) + " " + toLocalString(m_custom_help);
1329 
1330     if (m_positional.size() > 0 && m_positional_help.size() > 0) {
1331       result += " " + toLocalString(m_positional_help);
1332     }
1333 
1334     result += "\n\n";
1335 
1336     if (help_groups.size() == 0) {
1337       generate_all_groups_help(result);
1338     } else {
1339       generate_group_help(result, help_groups);
1340     }
1341 
1342     return toUTF8String(result);
1343   }
1344 
1345   inline const std::vector<std::string> Options::groups() const {
1346     std::vector<std::string> g;
1347 
1348     std::transform(m_help.begin(),
1349                    m_help.end(),
1350                    std::back_inserter(g),
1351                    [](const std::map<std::string, HelpGroupDetails>::value_type& pair) { return pair.first; });
1352 
1353     return g;
1354   }
1355 
1356   inline const HelpGroupDetails& Options::group_help(const std::string& group) const { return m_help.at(group); }
1357 
1358 }  // namespace cxxopts
1359 
1360 #endif  //CXXOPTS_HPP_INCLUDED