2293 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			2293 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C++
		
	
	
	
/*
 | 
						||
 | 
						||
Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck
 | 
						||
 | 
						||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
						||
of this software and associated documentation files (the "Software"), to deal
 | 
						||
in the Software without restriction, including without limitation the rights
 | 
						||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
						||
copies of the Software, and to permit persons to whom the Software is
 | 
						||
furnished to do so, subject to the following conditions:
 | 
						||
 | 
						||
The above copyright notice and this permission notice shall be included in
 | 
						||
all copies or substantial portions of the Software.
 | 
						||
 | 
						||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
						||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
						||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
						||
THE SOFTWARE.
 | 
						||
 | 
						||
*/
 | 
						||
 | 
						||
#ifndef CXXOPTS_HPP_INCLUDED
 | 
						||
#define CXXOPTS_HPP_INCLUDED
 | 
						||
 | 
						||
#include <cctype>
 | 
						||
#include <cstring>
 | 
						||
#include <exception>
 | 
						||
#include <iostream>
 | 
						||
#include <limits>
 | 
						||
#include <list>
 | 
						||
#include <map>
 | 
						||
#include <memory>
 | 
						||
#include <regex>
 | 
						||
#include <sstream>
 | 
						||
#include <string>
 | 
						||
#include <unordered_map>
 | 
						||
#include <unordered_set>
 | 
						||
#include <utility>
 | 
						||
#include <vector>
 | 
						||
 | 
						||
#ifdef __cpp_lib_optional
 | 
						||
#include <optional>
 | 
						||
#define CXXOPTS_HAS_OPTIONAL
 | 
						||
#endif
 | 
						||
 | 
						||
#if __cplusplus >= 201603L
 | 
						||
#define CXXOPTS_NODISCARD [[nodiscard]]
 | 
						||
#else
 | 
						||
#define CXXOPTS_NODISCARD
 | 
						||
#endif
 | 
						||
 | 
						||
#ifndef CXXOPTS_VECTOR_DELIMITER
 | 
						||
#define CXXOPTS_VECTOR_DELIMITER ','
 | 
						||
#endif
 | 
						||
 | 
						||
#define CXXOPTS__VERSION_MAJOR 3
 | 
						||
#define CXXOPTS__VERSION_MINOR 0
 | 
						||
#define CXXOPTS__VERSION_PATCH 0
 | 
						||
 | 
						||
namespace cxxopts
 | 
						||
{
 | 
						||
  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
 | 
						||
//compiler, and that icu-uc is linked in to the binary.
 | 
						||
 | 
						||
#ifdef CXXOPTS_USE_UNICODE
 | 
						||
#include <unicode/unistr.h>
 | 
						||
 | 
						||
namespace cxxopts
 | 
						||
{
 | 
						||
  typedef icu::UnicodeString String;
 | 
						||
 | 
						||
  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)
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    value_type
 | 
						||
    operator*() const
 | 
						||
    {
 | 
						||
      return s->char32At(i);
 | 
						||
    }
 | 
						||
 | 
						||
    bool
 | 
						||
    operator==(const UnicodeStringIterator& rhs) const
 | 
						||
    {
 | 
						||
      return s == rhs.s && i == rhs.i;
 | 
						||
    }
 | 
						||
 | 
						||
    bool
 | 
						||
    operator!=(const UnicodeStringIterator& rhs) const
 | 
						||
    {
 | 
						||
      return !(*this == rhs);
 | 
						||
    }
 | 
						||
 | 
						||
    UnicodeStringIterator&
 | 
						||
    operator++()
 | 
						||
    {
 | 
						||
      ++i;
 | 
						||
      return *this;
 | 
						||
    }
 | 
						||
 | 
						||
    UnicodeStringIterator
 | 
						||
    operator+(int32_t v)
 | 
						||
    {
 | 
						||
      return UnicodeStringIterator(s, i + v);
 | 
						||
    }
 | 
						||
 | 
						||
    private:
 | 
						||
    const icu::UnicodeString* s;
 | 
						||
    int32_t i;
 | 
						||
  };
 | 
						||
 | 
						||
  inline
 | 
						||
  String&
 | 
						||
  stringAppend(String&s, String a)
 | 
						||
  {
 | 
						||
    return s.append(std::move(a));
 | 
						||
  }
 | 
						||
 | 
						||
  inline
 | 
						||
  String&
 | 
						||
  stringAppend(String& s, size_t n, UChar32 c)
 | 
						||
  {
 | 
						||
    for (size_t i = 0; i != n; ++i)
 | 
						||
    {
 | 
						||
      s.append(c);
 | 
						||
    }
 | 
						||
 | 
						||
    return s;
 | 
						||
  }
 | 
						||
 | 
						||
  template <typename Iterator>
 | 
						||
  String&
 | 
						||
  stringAppend(String& s, Iterator begin, Iterator end)
 | 
						||
  {
 | 
						||
    while (begin != end)
 | 
						||
    {
 | 
						||
      s.append(*begin);
 | 
						||
      ++begin;
 | 
						||
    }
 | 
						||
 | 
						||
    return s;
 | 
						||
  }
 | 
						||
 | 
						||
  inline
 | 
						||
  size_t
 | 
						||
  stringLength(const String& s)
 | 
						||
  {
 | 
						||
    return s.length();
 | 
						||
  }
 | 
						||
 | 
						||
  inline
 | 
						||
  std::string
 | 
						||
  toUTF8String(const String& s)
 | 
						||
  {
 | 
						||
    std::string result;
 | 
						||
    s.toUTF8String(result);
 | 
						||
 | 
						||
    return result;
 | 
						||
  }
 | 
						||
 | 
						||
  inline
 | 
						||
  bool
 | 
						||
  empty(const String& s)
 | 
						||
  {
 | 
						||
    return s.isEmpty();
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
namespace std
 | 
						||
{
 | 
						||
  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());
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
//ifdef CXXOPTS_USE_UNICODE
 | 
						||
#else
 | 
						||
 | 
						||
namespace cxxopts
 | 
						||
{
 | 
						||
  typedef std::string String;
 | 
						||
 | 
						||
  template <typename T>
 | 
						||
  T
 | 
						||
  toLocalString(T&& t)
 | 
						||
  {
 | 
						||
    return std::forward<T>(t);
 | 
						||
  }
 | 
						||
 | 
						||
  inline
 | 
						||
  size_t
 | 
						||
  stringLength(const String& s)
 | 
						||
  {
 | 
						||
    return s.length();
 | 
						||
  }
 | 
						||
 | 
						||
  inline
 | 
						||
  String&
 | 
						||
  stringAppend(String&s, const String& a)
 | 
						||
  {
 | 
						||
    return s.append(a);
 | 
						||
  }
 | 
						||
 | 
						||
  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 T>
 | 
						||
  std::string
 | 
						||
  toUTF8String(T&& t)
 | 
						||
  {
 | 
						||
    return std::forward<T>(t);
 | 
						||
  }
 | 
						||
 | 
						||
  inline
 | 
						||
  bool
 | 
						||
  empty(const std::string& s)
 | 
						||
  {
 | 
						||
    return s.empty();
 | 
						||
  }
 | 
						||
} // namespace cxxopts
 | 
						||
 | 
						||
//ifdef CXXOPTS_USE_UNICODE
 | 
						||
#endif
 | 
						||
 | 
						||
namespace cxxopts
 | 
						||
{
 | 
						||
  namespace
 | 
						||
  {
 | 
						||
#ifdef _WIN32
 | 
						||
    const std::string LQUOTE("\'");
 | 
						||
    const std::string RQUOTE("\'");
 | 
						||
#else
 | 
						||
    const std::string LQUOTE("‘");
 | 
						||
    const std::string RQUOTE("’");
 | 
						||
#endif
 | 
						||
  } // namespace
 | 
						||
 | 
						||
#if defined(__GNUC__)
 | 
						||
// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it:
 | 
						||
// warning: base class 'class std::enable_shared_from_this<cxxopts::Value>' has accessible non-virtual destructor
 | 
						||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
 | 
						||
#pragma GCC diagnostic push
 | 
						||
// This will be ignored under other compilers like LLVM clang.
 | 
						||
#endif
 | 
						||
  class Value : public std::enable_shared_from_this<Value>
 | 
						||
  {
 | 
						||
    public:
 | 
						||
 | 
						||
    virtual ~Value() = default;
 | 
						||
 | 
						||
    virtual
 | 
						||
    std::shared_ptr<Value>
 | 
						||
    clone() const = 0;
 | 
						||
 | 
						||
    virtual void
 | 
						||
    parse(const std::string& text) const = 0;
 | 
						||
 | 
						||
    virtual void
 | 
						||
    parse() const = 0;
 | 
						||
 | 
						||
    virtual bool
 | 
						||
    has_default() const = 0;
 | 
						||
 | 
						||
    virtual bool
 | 
						||
    is_container() const = 0;
 | 
						||
 | 
						||
    virtual bool
 | 
						||
    has_implicit() const = 0;
 | 
						||
 | 
						||
    virtual std::string
 | 
						||
    get_default_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>
 | 
						||
    implicit_value(const std::string& value) = 0;
 | 
						||
 | 
						||
    virtual std::shared_ptr<Value>
 | 
						||
    no_implicit_value() = 0;
 | 
						||
 | 
						||
    virtual bool
 | 
						||
    is_boolean() const = 0;
 | 
						||
  };
 | 
						||
#if defined(__GNUC__)
 | 
						||
#pragma GCC diagnostic pop
 | 
						||
#endif
 | 
						||
  class OptionException : public std::exception
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    explicit OptionException(std::string  message)
 | 
						||
    : m_message(std::move(message))
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    CXXOPTS_NODISCARD
 | 
						||
    const char*
 | 
						||
    what() const noexcept override
 | 
						||
    {
 | 
						||
      return m_message.c_str();
 | 
						||
    }
 | 
						||
 | 
						||
    private:
 | 
						||
    std::string m_message;
 | 
						||
  };
 | 
						||
 | 
						||
  class OptionSpecException : public OptionException
 | 
						||
  {
 | 
						||
    public:
 | 
						||
 | 
						||
    explicit OptionSpecException(const std::string& message)
 | 
						||
    : OptionException(message)
 | 
						||
    {
 | 
						||
    }
 | 
						||
  };
 | 
						||
 | 
						||
  class OptionParseException : public OptionException
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    explicit OptionParseException(const std::string& message)
 | 
						||
    : OptionException(message)
 | 
						||
    {
 | 
						||
    }
 | 
						||
  };
 | 
						||
 | 
						||
  class option_exists_error : public OptionSpecException
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    explicit option_exists_error(const std::string& option)
 | 
						||
    : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists")
 | 
						||
    {
 | 
						||
    }
 | 
						||
  };
 | 
						||
 | 
						||
  class invalid_option_format_error : public OptionSpecException
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    explicit invalid_option_format_error(const std::string& format)
 | 
						||
    : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE)
 | 
						||
    {
 | 
						||
    }
 | 
						||
  };
 | 
						||
 | 
						||
  class option_syntax_exception : public OptionParseException {
 | 
						||
    public:
 | 
						||
    explicit 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:
 | 
						||
    explicit option_not_exists_exception(const std::string& option)
 | 
						||
    : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist")
 | 
						||
    {
 | 
						||
    }
 | 
						||
  };
 | 
						||
 | 
						||
  class missing_argument_exception : public OptionParseException
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    explicit missing_argument_exception(const std::string& option)
 | 
						||
    : OptionParseException(
 | 
						||
        "Option " + LQUOTE + option + RQUOTE + " is missing an argument"
 | 
						||
      )
 | 
						||
    {
 | 
						||
    }
 | 
						||
  };
 | 
						||
 | 
						||
  class option_requires_argument_exception : public OptionParseException
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    explicit 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
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    explicit option_not_present_exception(const std::string& option)
 | 
						||
    : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present")
 | 
						||
    {
 | 
						||
    }
 | 
						||
  };
 | 
						||
 | 
						||
  class option_has_no_value_exception : public OptionException
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    explicit option_has_no_value_exception(const std::string& option)
 | 
						||
    : OptionException(
 | 
						||
        option.empty() ?
 | 
						||
        ("Option " + LQUOTE + option + RQUOTE + " has no value") :
 | 
						||
        "Option has no value")
 | 
						||
    {
 | 
						||
    }
 | 
						||
  };
 | 
						||
 | 
						||
  class argument_incorrect_type : public OptionParseException
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    explicit argument_incorrect_type
 | 
						||
    (
 | 
						||
      const std::string& arg
 | 
						||
    )
 | 
						||
    : OptionParseException(
 | 
						||
        "Argument " + LQUOTE + arg + RQUOTE + " failed to parse"
 | 
						||
      )
 | 
						||
    {
 | 
						||
    }
 | 
						||
  };
 | 
						||
 | 
						||
  class option_required_exception : public OptionParseException
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    explicit 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)
 | 
						||
  {
 | 
						||
    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};
 | 
						||
#else
 | 
						||
    // Otherwise manually instantiate the exception, print what() to stderr,
 | 
						||
    // and exit
 | 
						||
    T exception{text};
 | 
						||
    std::cerr << exception.what() << std::endl;
 | 
						||
    std::exit(EXIT_FAILURE);
 | 
						||
#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
 | 
						||
 | 
						||
    namespace detail
 | 
						||
    {
 | 
						||
      template <typename T, bool B>
 | 
						||
      struct SignedCheck;
 | 
						||
 | 
						||
      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);
 | 
						||
            }
 | 
						||
          }
 | 
						||
        }
 | 
						||
      };
 | 
						||
 | 
						||
      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)
 | 
						||
      {
 | 
						||
        SignedCheck<T, std::numeric_limits<T>::is_signed>()(negative, value, text);
 | 
						||
      }
 | 
						||
    } // namespace detail
 | 
						||
 | 
						||
    template <typename R, typename T>
 | 
						||
    void
 | 
						||
    checked_negate(R& r, 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.
 | 
						||
      r = static_cast<R>(-static_cast<R>(t-1)-1);
 | 
						||
    }
 | 
						||
 | 
						||
    template <typename R, typename T>
 | 
						||
    void
 | 
						||
    checked_negate(R&, T&&, const std::string& text, std::false_type)
 | 
						||
    {
 | 
						||
      throw_or_mimic<argument_incorrect_type>(text);
 | 
						||
    }
 | 
						||
 | 
						||
    template <typename T>
 | 
						||
    void
 | 
						||
    integer_parser(const std::string& text, T& value)
 | 
						||
    {
 | 
						||
      std::smatch match;
 | 
						||
      std::regex_match(text, match, integer_pattern);
 | 
						||
 | 
						||
      if (match.length() == 0)
 | 
						||
      {
 | 
						||
        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;
 | 
						||
 | 
						||
        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);
 | 
						||
        }
 | 
						||
 | 
						||
        const US next = static_cast<US>(result * base + digit);
 | 
						||
        if (result > next)
 | 
						||
        {
 | 
						||
          throw_or_mimic<argument_incorrect_type>(text);
 | 
						||
        }
 | 
						||
 | 
						||
        result = next;
 | 
						||
      }
 | 
						||
 | 
						||
      detail::check_signed_range<T>(negative, result, text);
 | 
						||
 | 
						||
      if (negative)
 | 
						||
      {
 | 
						||
        checked_negate<T>(value, result, text, std::integral_constant<bool, is_signed>());
 | 
						||
      }
 | 
						||
      else
 | 
						||
      {
 | 
						||
        value = static_cast<T>(result);
 | 
						||
      }
 | 
						||
    }
 | 
						||
 | 
						||
    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);
 | 
						||
      }
 | 
						||
    }
 | 
						||
 | 
						||
    inline
 | 
						||
    void
 | 
						||
    parse_value(const std::string& text, uint8_t& value)
 | 
						||
    {
 | 
						||
      integer_parser(text, value);
 | 
						||
    }
 | 
						||
 | 
						||
    inline
 | 
						||
    void
 | 
						||
    parse_value(const std::string& text, int8_t& value)
 | 
						||
    {
 | 
						||
      integer_parser(text, value);
 | 
						||
    }
 | 
						||
 | 
						||
    inline
 | 
						||
    void
 | 
						||
    parse_value(const std::string& text, uint16_t& value)
 | 
						||
    {
 | 
						||
      integer_parser(text, value);
 | 
						||
    }
 | 
						||
 | 
						||
    inline
 | 
						||
    void
 | 
						||
    parse_value(const std::string& text, int16_t& value)
 | 
						||
    {
 | 
						||
      integer_parser(text, value);
 | 
						||
    }
 | 
						||
 | 
						||
    inline
 | 
						||
    void
 | 
						||
    parse_value(const std::string& text, uint32_t& value)
 | 
						||
    {
 | 
						||
      integer_parser(text, value);
 | 
						||
    }
 | 
						||
 | 
						||
    inline
 | 
						||
    void
 | 
						||
    parse_value(const std::string& text, int32_t& value)
 | 
						||
    {
 | 
						||
      integer_parser(text, value);
 | 
						||
    }
 | 
						||
 | 
						||
    inline
 | 
						||
    void
 | 
						||
    parse_value(const std::string& text, uint64_t& value)
 | 
						||
    {
 | 
						||
      integer_parser(text, value);
 | 
						||
    }
 | 
						||
 | 
						||
    inline
 | 
						||
    void
 | 
						||
    parse_value(const std::string& text, int64_t& value)
 | 
						||
    {
 | 
						||
      integer_parser(text, value);
 | 
						||
    }
 | 
						||
 | 
						||
    inline
 | 
						||
    void
 | 
						||
    parse_value(const std::string& text, bool& value)
 | 
						||
    {
 | 
						||
      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)
 | 
						||
    {
 | 
						||
      value = 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);
 | 
						||
    }
 | 
						||
 | 
						||
    template <typename T>
 | 
						||
    void
 | 
						||
    parse_value(const std::string& text, std::vector<T>& value)
 | 
						||
    {
 | 
						||
      std::stringstream in(text);
 | 
						||
      std::string token;
 | 
						||
      while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
 | 
						||
        T v;
 | 
						||
        parse_value(token, v);
 | 
						||
        value.emplace_back(std::move(v));
 | 
						||
      }
 | 
						||
    }
 | 
						||
 | 
						||
#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
 | 
						||
 | 
						||
    inline
 | 
						||
    void parse_value(const std::string& text, char& c)
 | 
						||
    {
 | 
						||
      if (text.length() != 1)
 | 
						||
      {
 | 
						||
        throw_or_mimic<argument_incorrect_type>(text);
 | 
						||
      }
 | 
						||
 | 
						||
      c = text[0];
 | 
						||
    }
 | 
						||
 | 
						||
    template <typename T>
 | 
						||
    struct type_is_container
 | 
						||
    {
 | 
						||
      static constexpr bool value = false;
 | 
						||
    };
 | 
						||
 | 
						||
    template <typename T>
 | 
						||
    struct type_is_container<std::vector<T>>
 | 
						||
    {
 | 
						||
      static constexpr bool value = true;
 | 
						||
    };
 | 
						||
 | 
						||
    template <typename T>
 | 
						||
    class abstract_value : public Value
 | 
						||
    {
 | 
						||
      using Self = abstract_value<T>;
 | 
						||
 | 
						||
      public:
 | 
						||
      abstract_value()
 | 
						||
      : m_result(std::make_shared<T>())
 | 
						||
      , m_store(m_result.get())
 | 
						||
      {
 | 
						||
      }
 | 
						||
 | 
						||
      explicit abstract_value(T* t)
 | 
						||
      : m_store(t)
 | 
						||
      {
 | 
						||
      }
 | 
						||
 | 
						||
      ~abstract_value() override = default;
 | 
						||
 | 
						||
      abstract_value& operator=(const abstract_value&) = default;
 | 
						||
 | 
						||
      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;
 | 
						||
        }
 | 
						||
 | 
						||
        m_default = rhs.m_default;
 | 
						||
        m_implicit = rhs.m_implicit;
 | 
						||
        m_default_value = rhs.m_default_value;
 | 
						||
        m_implicit_value = rhs.m_implicit_value;
 | 
						||
      }
 | 
						||
 | 
						||
      void
 | 
						||
      parse(const std::string& text) const override
 | 
						||
      {
 | 
						||
        parse_value(text, *m_store);
 | 
						||
      }
 | 
						||
 | 
						||
      bool
 | 
						||
      is_container() const override
 | 
						||
      {
 | 
						||
        return type_is_container<T>::value;
 | 
						||
      }
 | 
						||
 | 
						||
      void
 | 
						||
      parse() const override
 | 
						||
      {
 | 
						||
        parse_value(m_default_value, *m_store);
 | 
						||
      }
 | 
						||
 | 
						||
      bool
 | 
						||
      has_default() const override
 | 
						||
      {
 | 
						||
        return m_default;
 | 
						||
      }
 | 
						||
 | 
						||
      bool
 | 
						||
      has_implicit() const override
 | 
						||
      {
 | 
						||
        return m_implicit;
 | 
						||
      }
 | 
						||
 | 
						||
      std::shared_ptr<Value>
 | 
						||
      default_value(const std::string& value) override
 | 
						||
      {
 | 
						||
        m_default = true;
 | 
						||
        m_default_value = value;
 | 
						||
        return shared_from_this();
 | 
						||
      }
 | 
						||
 | 
						||
      std::shared_ptr<Value>
 | 
						||
      implicit_value(const std::string& value) override
 | 
						||
      {
 | 
						||
        m_implicit = true;
 | 
						||
        m_implicit_value = value;
 | 
						||
        return shared_from_this();
 | 
						||
      }
 | 
						||
 | 
						||
      std::shared_ptr<Value>
 | 
						||
      no_implicit_value() override
 | 
						||
      {
 | 
						||
        m_implicit = false;
 | 
						||
        return shared_from_this();
 | 
						||
      }
 | 
						||
 | 
						||
      std::string
 | 
						||
      get_default_value() const override
 | 
						||
      {
 | 
						||
        return m_default_value;
 | 
						||
      }
 | 
						||
 | 
						||
      std::string
 | 
						||
      get_implicit_value() const override
 | 
						||
      {
 | 
						||
        return m_implicit_value;
 | 
						||
      }
 | 
						||
 | 
						||
      bool
 | 
						||
      is_boolean() const override
 | 
						||
      {
 | 
						||
        return std::is_same<T, bool>::value;
 | 
						||
      }
 | 
						||
 | 
						||
      const T&
 | 
						||
      get() const
 | 
						||
      {
 | 
						||
        if (m_store == nullptr)
 | 
						||
        {
 | 
						||
          return *m_result;
 | 
						||
        }
 | 
						||
        return *m_store;
 | 
						||
      }
 | 
						||
 | 
						||
      protected:
 | 
						||
      std::shared_ptr<T> m_result{};
 | 
						||
      T* m_store{};
 | 
						||
 | 
						||
      bool m_default = false;
 | 
						||
      bool m_implicit = false;
 | 
						||
 | 
						||
      std::string m_default_value{};
 | 
						||
      std::string m_implicit_value{};
 | 
						||
    };
 | 
						||
 | 
						||
    template <typename T>
 | 
						||
    class standard_value : public abstract_value<T>
 | 
						||
    {
 | 
						||
      public:
 | 
						||
      using abstract_value<T>::abstract_value;
 | 
						||
 | 
						||
      CXXOPTS_NODISCARD
 | 
						||
      std::shared_ptr<Value>
 | 
						||
      clone() const
 | 
						||
      {
 | 
						||
        return std::make_shared<standard_value<T>>(*this);
 | 
						||
      }
 | 
						||
    };
 | 
						||
 | 
						||
    template <>
 | 
						||
    class standard_value<bool> : public abstract_value<bool>
 | 
						||
    {
 | 
						||
      public:
 | 
						||
      ~standard_value() override = default;
 | 
						||
 | 
						||
      standard_value()
 | 
						||
      {
 | 
						||
        set_default_and_implicit();
 | 
						||
      }
 | 
						||
 | 
						||
      explicit standard_value(bool* b)
 | 
						||
      : abstract_value(b)
 | 
						||
      {
 | 
						||
        set_default_and_implicit();
 | 
						||
      }
 | 
						||
 | 
						||
      std::shared_ptr<Value>
 | 
						||
      clone() const override
 | 
						||
      {
 | 
						||
        return std::make_shared<standard_value<bool>>(*this);
 | 
						||
      }
 | 
						||
 | 
						||
      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>
 | 
						||
  std::shared_ptr<Value>
 | 
						||
  value()
 | 
						||
  {
 | 
						||
    return std::make_shared<values::standard_value<T>>();
 | 
						||
  }
 | 
						||
 | 
						||
  template <typename T>
 | 
						||
  std::shared_ptr<Value>
 | 
						||
  value(T& t)
 | 
						||
  {
 | 
						||
    return std::make_shared<values::standard_value<T>>(&t);
 | 
						||
  }
 | 
						||
 | 
						||
  class OptionAdder;
 | 
						||
 | 
						||
  class OptionDetails
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    OptionDetails
 | 
						||
    (
 | 
						||
      std::string short_,
 | 
						||
      std::string long_,
 | 
						||
      String desc,
 | 
						||
      std::shared_ptr<const Value> val
 | 
						||
    )
 | 
						||
    : m_short(std::move(short_))
 | 
						||
    , m_long(std::move(long_))
 | 
						||
    , m_desc(std::move(desc))
 | 
						||
    , m_value(std::move(val))
 | 
						||
    , m_count(0)
 | 
						||
    {
 | 
						||
      m_hash = std::hash<std::string>{}(m_long + m_short);
 | 
						||
    }
 | 
						||
 | 
						||
    OptionDetails(const OptionDetails& rhs)
 | 
						||
    : m_desc(rhs.m_desc)
 | 
						||
    , m_count(rhs.m_count)
 | 
						||
    {
 | 
						||
      m_value = rhs.m_value->clone();
 | 
						||
    }
 | 
						||
 | 
						||
    OptionDetails(OptionDetails&& rhs) = default;
 | 
						||
 | 
						||
    CXXOPTS_NODISCARD
 | 
						||
    const String&
 | 
						||
    description() const
 | 
						||
    {
 | 
						||
      return m_desc;
 | 
						||
    }
 | 
						||
 | 
						||
    CXXOPTS_NODISCARD
 | 
						||
    const Value&
 | 
						||
    value() const {
 | 
						||
        return *m_value;
 | 
						||
    }
 | 
						||
 | 
						||
    CXXOPTS_NODISCARD
 | 
						||
    std::shared_ptr<Value>
 | 
						||
    make_storage() const
 | 
						||
    {
 | 
						||
      return m_value->clone();
 | 
						||
    }
 | 
						||
 | 
						||
    CXXOPTS_NODISCARD
 | 
						||
    const std::string&
 | 
						||
    short_name() const
 | 
						||
    {
 | 
						||
      return m_short;
 | 
						||
    }
 | 
						||
 | 
						||
    CXXOPTS_NODISCARD
 | 
						||
    const std::string&
 | 
						||
    long_name() const
 | 
						||
    {
 | 
						||
      return m_long;
 | 
						||
    }
 | 
						||
 | 
						||
    size_t
 | 
						||
    hash() const
 | 
						||
    {
 | 
						||
      return m_hash;
 | 
						||
    }
 | 
						||
 | 
						||
    private:
 | 
						||
    std::string m_short{};
 | 
						||
    std::string m_long{};
 | 
						||
    String m_desc{};
 | 
						||
    std::shared_ptr<const Value> m_value{};
 | 
						||
    int m_count;
 | 
						||
 | 
						||
    size_t m_hash{};
 | 
						||
  };
 | 
						||
 | 
						||
  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
 | 
						||
    (
 | 
						||
      const std::shared_ptr<const OptionDetails>& details,
 | 
						||
      const std::string& text
 | 
						||
    )
 | 
						||
    {
 | 
						||
      ensure_value(details);
 | 
						||
      ++m_count;
 | 
						||
      m_value->parse(text);
 | 
						||
      m_long_name = &details->long_name();
 | 
						||
    }
 | 
						||
 | 
						||
    void
 | 
						||
    parse_default(const std::shared_ptr<const OptionDetails>& details)
 | 
						||
    {
 | 
						||
      ensure_value(details);
 | 
						||
      m_default = true;
 | 
						||
      m_long_name = &details->long_name();
 | 
						||
      m_value->parse();
 | 
						||
    }
 | 
						||
 | 
						||
    CXXOPTS_NODISCARD
 | 
						||
    size_t
 | 
						||
    count() const noexcept
 | 
						||
    {
 | 
						||
      return m_count;
 | 
						||
    }
 | 
						||
 | 
						||
    // TODO: maybe default options should count towards the number of arguments
 | 
						||
    CXXOPTS_NODISCARD
 | 
						||
    bool
 | 
						||
    has_default() const noexcept
 | 
						||
    {
 | 
						||
      return m_default;
 | 
						||
    }
 | 
						||
 | 
						||
    template <typename T>
 | 
						||
    const T&
 | 
						||
    as() const
 | 
						||
    {
 | 
						||
      if (m_value == nullptr) {
 | 
						||
          throw_or_mimic<option_has_no_value_exception>(
 | 
						||
              m_long_name == nullptr ? "" : *m_long_name);
 | 
						||
      }
 | 
						||
 | 
						||
#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(const std::shared_ptr<const OptionDetails>& details)
 | 
						||
    {
 | 
						||
      if (m_value == nullptr)
 | 
						||
      {
 | 
						||
        m_value = details->make_storage();
 | 
						||
      }
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    const std::string* m_long_name = nullptr;
 | 
						||
    // Holding this pointer is safe, since OptionValue's only exist in key-value pairs,
 | 
						||
    // where the key has the string we point to.
 | 
						||
    std::shared_ptr<Value> m_value{};
 | 
						||
    size_t m_count = 0;
 | 
						||
    bool m_default = false;
 | 
						||
  };
 | 
						||
 | 
						||
  class KeyValue
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    KeyValue(std::string key_, std::string value_)
 | 
						||
    : m_key(std::move(key_))
 | 
						||
    , m_value(std::move(value_))
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    CXXOPTS_NODISCARD
 | 
						||
    const std::string&
 | 
						||
    key() const
 | 
						||
    {
 | 
						||
      return m_key;
 | 
						||
    }
 | 
						||
 | 
						||
    CXXOPTS_NODISCARD
 | 
						||
    const std::string&
 | 
						||
    value() const
 | 
						||
    {
 | 
						||
      return m_value;
 | 
						||
    }
 | 
						||
 | 
						||
    template <typename T>
 | 
						||
    T
 | 
						||
    as() const
 | 
						||
    {
 | 
						||
      T result;
 | 
						||
      values::parse_value(m_value, result);
 | 
						||
      return result;
 | 
						||
    }
 | 
						||
 | 
						||
    private:
 | 
						||
    std::string m_key;
 | 
						||
    std::string m_value;
 | 
						||
  };
 | 
						||
 | 
						||
  using ParsedHashMap = std::unordered_map<size_t, OptionValue>;
 | 
						||
  using NameHashMap = std::unordered_map<std::string, size_t>;
 | 
						||
 | 
						||
  class ParseResult
 | 
						||
  {
 | 
						||
    public:
 | 
						||
 | 
						||
    ParseResult() {}
 | 
						||
     
 | 
						||
    ParseResult(const ParseResult&) = default;
 | 
						||
 | 
						||
    ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<KeyValue> sequential, std::vector<std::string>&& unmatched_args)
 | 
						||
    : m_keys(std::move(keys))
 | 
						||
    , m_values(std::move(values))
 | 
						||
    , m_sequential(std::move(sequential))
 | 
						||
    , m_unmatched(std::move(unmatched_args))
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    ParseResult& operator=(ParseResult&&) = default;
 | 
						||
    ParseResult& operator=(const ParseResult&) = default;
 | 
						||
 | 
						||
    size_t
 | 
						||
    count(const std::string& o) const
 | 
						||
    {
 | 
						||
      auto iter = m_keys.find(o);
 | 
						||
      if (iter == m_keys.end())
 | 
						||
      {
 | 
						||
        return 0;
 | 
						||
      }
 | 
						||
 | 
						||
      auto viter = m_values.find(iter->second);
 | 
						||
 | 
						||
      if (viter == m_values.end())
 | 
						||
      {
 | 
						||
        return 0;
 | 
						||
      }
 | 
						||
 | 
						||
      return viter->second.count();
 | 
						||
    }
 | 
						||
 | 
						||
    const OptionValue&
 | 
						||
    operator[](const std::string& option) const
 | 
						||
    {
 | 
						||
      auto iter = m_keys.find(option);
 | 
						||
 | 
						||
      if (iter == m_keys.end())
 | 
						||
      {
 | 
						||
        throw_or_mimic<option_not_present_exception>(option);
 | 
						||
      }
 | 
						||
 | 
						||
      auto viter = m_values.find(iter->second);
 | 
						||
 | 
						||
      if (viter == m_values.end())
 | 
						||
      {
 | 
						||
        throw_or_mimic<option_not_present_exception>(option);
 | 
						||
      }
 | 
						||
 | 
						||
      return viter->second;
 | 
						||
    }
 | 
						||
 | 
						||
    const std::vector<KeyValue>&
 | 
						||
    arguments() const
 | 
						||
    {
 | 
						||
      return m_sequential;
 | 
						||
    }
 | 
						||
 | 
						||
    const std::vector<std::string>&
 | 
						||
    unmatched() const
 | 
						||
    {
 | 
						||
      return m_unmatched;
 | 
						||
    }
 | 
						||
 | 
						||
    private:
 | 
						||
    NameHashMap m_keys{};
 | 
						||
    ParsedHashMap m_values{};
 | 
						||
    std::vector<KeyValue> m_sequential{};
 | 
						||
    std::vector<std::string> m_unmatched{};
 | 
						||
  };
 | 
						||
 | 
						||
  struct Option
 | 
						||
  {
 | 
						||
    Option
 | 
						||
    (
 | 
						||
      std::string opts,
 | 
						||
      std::string desc,
 | 
						||
      std::shared_ptr<const Value>  value = ::cxxopts::value<bool>(),
 | 
						||
      std::string arg_help = ""
 | 
						||
    )
 | 
						||
    : opts_(std::move(opts))
 | 
						||
    , desc_(std::move(desc))
 | 
						||
    , value_(std::move(value))
 | 
						||
    , arg_help_(std::move(arg_help))
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    std::string opts_;
 | 
						||
    std::string desc_;
 | 
						||
    std::shared_ptr<const Value> value_;
 | 
						||
    std::string arg_help_;
 | 
						||
  };
 | 
						||
 | 
						||
  using OptionMap = std::unordered_map<std::string, std::shared_ptr<OptionDetails>>;
 | 
						||
  using PositionalList = std::vector<std::string>;
 | 
						||
  using PositionalListIterator = PositionalList::const_iterator;
 | 
						||
 | 
						||
  class OptionParser
 | 
						||
  {
 | 
						||
    public:
 | 
						||
    OptionParser(const OptionMap& options, const PositionalList& positional, bool allow_unrecognised)
 | 
						||
    : m_options(options)
 | 
						||
    , m_positional(positional)
 | 
						||
    , m_allow_unrecognised(allow_unrecognised)
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    ParseResult
 | 
						||
    parse(int argc, const char* const* argv);
 | 
						||
 | 
						||
    bool
 | 
						||
    consume_positional(const std::string& a, PositionalListIterator& next);
 | 
						||
 | 
						||
    void
 | 
						||
    checked_parse_arg
 | 
						||
    (
 | 
						||
      int argc,
 | 
						||
      const char* const* argv,
 | 
						||
      int& current,
 | 
						||
      const std::shared_ptr<OptionDetails>& value,
 | 
						||
      const std::string& name
 | 
						||
    );
 | 
						||
 | 
						||
    void
 | 
						||
    add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg);
 | 
						||
 | 
						||
    void
 | 
						||
    parse_option
 | 
						||
    (
 | 
						||
      const std::shared_ptr<OptionDetails>& value,
 | 
						||
      const std::string& name,
 | 
						||
      const std::string& arg = ""
 | 
						||
    );
 | 
						||
 | 
						||
    void
 | 
						||
    parse_default(const std::shared_ptr<OptionDetails>& details);
 | 
						||
 | 
						||
    private:
 | 
						||
 | 
						||
    void finalise_aliases();
 | 
						||
 | 
						||
    const OptionMap& m_options;
 | 
						||
    const PositionalList& m_positional;
 | 
						||
 | 
						||
    std::vector<KeyValue> m_sequential{};
 | 
						||
    bool m_allow_unrecognised;
 | 
						||
 | 
						||
    ParsedHashMap m_parsed{};
 | 
						||
    NameHashMap m_keys{};
 | 
						||
  };
 | 
						||
 | 
						||
  class Options
 | 
						||
  {
 | 
						||
    public:
 | 
						||
 | 
						||
    explicit 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>())
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    Options&
 | 
						||
    positional_help(std::string help_text)
 | 
						||
    {
 | 
						||
      m_positional_help = std::move(help_text);
 | 
						||
      return *this;
 | 
						||
    }
 | 
						||
 | 
						||
    Options&
 | 
						||
    custom_help(std::string help_text)
 | 
						||
    {
 | 
						||
      m_custom_help = std::move(help_text);
 | 
						||
      return *this;
 | 
						||
    }
 | 
						||
 | 
						||
    Options&
 | 
						||
    show_positional_help()
 | 
						||
    {
 | 
						||
      m_show_positional = true;
 | 
						||
      return *this;
 | 
						||
    }
 | 
						||
 | 
						||
    Options&
 | 
						||
    allow_unrecognised_options()
 | 
						||
    {
 | 
						||
      m_allow_unrecognised = true;
 | 
						||
      return *this;
 | 
						||
    }
 | 
						||
 | 
						||
    ParseResult
 | 
						||
    parse(int argc, const char* const* 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,
 | 
						||
      const 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});
 | 
						||
    }
 | 
						||
 | 
						||
    std::string
 | 
						||
    help(const std::vector<std::string>& groups = {}) const;
 | 
						||
 | 
						||
    std::vector<std::string>
 | 
						||
    groups() const;
 | 
						||
 | 
						||
    const HelpGroupDetails&
 | 
						||
    group_help(const std::string& group) const;
 | 
						||
 | 
						||
    private:
 | 
						||
 | 
						||
    void
 | 
						||
    add_one_option
 | 
						||
    (
 | 
						||
      const std::string& option,
 | 
						||
      const std::shared_ptr<OptionDetails>& details
 | 
						||
    );
 | 
						||
 | 
						||
    String
 | 
						||
    help_one_group(const std::string& group) const;
 | 
						||
 | 
						||
    void
 | 
						||
    generate_group_help
 | 
						||
    (
 | 
						||
      String& result,
 | 
						||
      const std::vector<std::string>& groups
 | 
						||
    ) const;
 | 
						||
 | 
						||
    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::unordered_set<std::string> m_positional_set{};
 | 
						||
 | 
						||
    //mapping from groups to help options
 | 
						||
    std::map<std::string, HelpGroupDetails> m_help{};
 | 
						||
 | 
						||
    std::list<OptionDetails> m_option_list{};
 | 
						||
    std::unordered_map<std::string, decltype(m_option_list)::iterator> m_option_map{};
 | 
						||
  };
 | 
						||
 | 
						||
  class OptionAdder
 | 
						||
  {
 | 
						||
    public:
 | 
						||
 | 
						||
    OptionAdder(Options& options, std::string group)
 | 
						||
    : m_options(options), m_group(std::move(group))
 | 
						||
    {
 | 
						||
    }
 | 
						||
 | 
						||
    OptionAdder&
 | 
						||
    operator()
 | 
						||
    (
 | 
						||
      const std::string& opts,
 | 
						||
      const std::string& desc,
 | 
						||
      const 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
 | 
						||
    )
 | 
						||
    {
 | 
						||
      const auto& s = o.s;
 | 
						||
      const auto& l = o.l;
 | 
						||
 | 
						||
      String result = "  ";
 | 
						||
 | 
						||
      if (!s.empty())
 | 
						||
      {
 | 
						||
        result += "-" + toLocalString(s);
 | 
						||
        if (!l.empty())
 | 
						||
        {
 | 
						||
          result += ",";
 | 
						||
        }
 | 
						||
      }
 | 
						||
      else
 | 
						||
      {
 | 
						||
        result += "   ";
 | 
						||
      }
 | 
						||
 | 
						||
      if (!l.empty())
 | 
						||
      {
 | 
						||
        result += " --" + toLocalString(l);
 | 
						||
      }
 | 
						||
 | 
						||
      auto arg = !o.arg_help.empty() ? toLocalString(o.arg_help) : "arg";
 | 
						||
 | 
						||
      if (!o.is_boolean)
 | 
						||
      {
 | 
						||
        if (o.has_implicit)
 | 
						||
        {
 | 
						||
          result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
 | 
						||
        }
 | 
						||
        else
 | 
						||
        {
 | 
						||
          result += " " + arg;
 | 
						||
        }
 | 
						||
      }
 | 
						||
 | 
						||
      return result;
 | 
						||
    }
 | 
						||
 | 
						||
    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.empty())
 | 
						||
        {
 | 
						||
          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 == ' ')
 | 
						||
        {
 | 
						||
          lastSpace = current;
 | 
						||
        }
 | 
						||
 | 
						||
        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;
 | 
						||
        }
 | 
						||
 | 
						||
        ++current;
 | 
						||
      }
 | 
						||
 | 
						||
      //append whatever is left
 | 
						||
      stringAppend(result, startLine, current);
 | 
						||
 | 
						||
      return result;
 | 
						||
    }
 | 
						||
  } // namespace
 | 
						||
 | 
						||
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_);
 | 
						||
 }
 | 
						||
}
 | 
						||
 | 
						||
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,
 | 
						||
  const 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())
 | 
						||
  {
 | 
						||
    throw_or_mimic<invalid_option_format_error>(opts);
 | 
						||
  }
 | 
						||
 | 
						||
  const auto& short_match = result[2];
 | 
						||
  const auto& long_match = result[3];
 | 
						||
 | 
						||
  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);
 | 
						||
  }
 | 
						||
 | 
						||
  auto option_names = []
 | 
						||
  (
 | 
						||
    const std::sub_match<const char*>& short_,
 | 
						||
    const std::sub_match<const char*>& long_
 | 
						||
  )
 | 
						||
  {
 | 
						||
    if (long_.length() == 1)
 | 
						||
    {
 | 
						||
      return std::make_tuple(long_.str(), short_.str());
 | 
						||
    }
 | 
						||
    return std::make_tuple(short_.str(), long_.str());
 | 
						||
  }(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)
 | 
						||
  );
 | 
						||
 | 
						||
  return *this;
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
void
 | 
						||
OptionParser::parse_default(const std::shared_ptr<OptionDetails>& details)
 | 
						||
{
 | 
						||
  // TODO: remove the duplicate code here
 | 
						||
  auto& store = m_parsed[details->hash()];
 | 
						||
  store.parse_default(details);
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
void
 | 
						||
OptionParser::parse_option
 | 
						||
(
 | 
						||
  const std::shared_ptr<OptionDetails>& value,
 | 
						||
  const std::string& /*name*/,
 | 
						||
  const std::string& arg
 | 
						||
)
 | 
						||
{
 | 
						||
  auto hash = value->hash();
 | 
						||
  auto& result = m_parsed[hash];
 | 
						||
  result.parse(value, arg);
 | 
						||
 | 
						||
  m_sequential.emplace_back(value->long_name(), arg);
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
void
 | 
						||
OptionParser::checked_parse_arg
 | 
						||
(
 | 
						||
  int argc,
 | 
						||
  const char* const* argv,
 | 
						||
  int& current,
 | 
						||
  const 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<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;
 | 
						||
    }
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
void
 | 
						||
OptionParser::add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg)
 | 
						||
{
 | 
						||
  parse_option(iter->second, option, arg);
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
bool
 | 
						||
OptionParser::consume_positional(const std::string& a, PositionalListIterator& next)
 | 
						||
{
 | 
						||
  while (next != m_positional.end())
 | 
						||
  {
 | 
						||
    auto iter = m_options.find(*next);
 | 
						||
    if (iter != m_options.end())
 | 
						||
    {
 | 
						||
      auto& result = m_parsed[iter->second->hash()];
 | 
						||
      if (!iter->second->value().is_container())
 | 
						||
      {
 | 
						||
        if (result.count() == 0)
 | 
						||
        {
 | 
						||
          add_to_option(iter, *next, a);
 | 
						||
          ++next;
 | 
						||
          return true;
 | 
						||
        }
 | 
						||
        ++next;
 | 
						||
        continue;
 | 
						||
      }
 | 
						||
      add_to_option(iter, *next, a);
 | 
						||
      return true;
 | 
						||
    }
 | 
						||
    throw_or_mimic<option_not_exists_exception>(*next);
 | 
						||
  }
 | 
						||
 | 
						||
  return false;
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
void
 | 
						||
Options::parse_positional(std::string option)
 | 
						||
{
 | 
						||
  parse_positional(std::vector<std::string>{std::move(option)});
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
void
 | 
						||
Options::parse_positional(std::vector<std::string> options)
 | 
						||
{
 | 
						||
  m_positional = std::move(options);
 | 
						||
 | 
						||
  m_positional_set.insert(m_positional.begin(), m_positional.end());
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
void
 | 
						||
Options::parse_positional(std::initializer_list<std::string> options)
 | 
						||
{
 | 
						||
  parse_positional(std::vector<std::string>(options));
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
ParseResult
 | 
						||
Options::parse(int argc, const char* const* argv)
 | 
						||
{
 | 
						||
  OptionParser parser(*m_options, m_positional, m_allow_unrecognised);
 | 
						||
 | 
						||
  return parser.parse(argc, argv);
 | 
						||
}
 | 
						||
 | 
						||
inline ParseResult
 | 
						||
OptionParser::parse(int argc, const char* const* argv)
 | 
						||
{
 | 
						||
  int current = 1;
 | 
						||
  bool consume_remaining = false;
 | 
						||
  PositionalListIterator next_positional = m_positional.begin();
 | 
						||
 | 
						||
  std::vector<std::string> unmatched;
 | 
						||
 | 
						||
  while (current != argc)
 | 
						||
  {
 | 
						||
    if (strcmp(argv[current], "--") == 0)
 | 
						||
    {
 | 
						||
      consume_remaining = true;
 | 
						||
      ++current;
 | 
						||
      break;
 | 
						||
    }
 | 
						||
 | 
						||
    std::match_results<const char*> result;
 | 
						||
    std::regex_match(argv[current], result, option_matcher);
 | 
						||
 | 
						||
    if (result.empty())
 | 
						||
    {
 | 
						||
      //not a flag
 | 
						||
 | 
						||
      // 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 true is returned here then it was consumed, otherwise it is
 | 
						||
      //ignored
 | 
						||
      if (consume_positional(argv[current], next_positional))
 | 
						||
      {
 | 
						||
      }
 | 
						||
      else
 | 
						||
      {
 | 
						||
        unmatched.push_back(argv[current]);
 | 
						||
      }
 | 
						||
      //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];
 | 
						||
 | 
						||
        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;
 | 
						||
            }
 | 
						||
            //error
 | 
						||
            throw_or_mimic<option_not_exists_exception>(name);
 | 
						||
          }
 | 
						||
 | 
						||
          auto value = iter->second;
 | 
						||
 | 
						||
          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)
 | 
						||
      {
 | 
						||
        const std::string& name = result[1];
 | 
						||
 | 
						||
        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
 | 
						||
            unmatched.push_back(argv[current]);
 | 
						||
            ++current;
 | 
						||
            continue;
 | 
						||
          }
 | 
						||
          //error
 | 
						||
          throw_or_mimic<option_not_exists_exception>(name);
 | 
						||
        }
 | 
						||
 | 
						||
        auto opt = iter->second;
 | 
						||
 | 
						||
        //equals provided for long option?
 | 
						||
        if (result[2].length() != 0)
 | 
						||
        {
 | 
						||
          //parse the option given
 | 
						||
 | 
						||
          parse_option(opt, name, result[3]);
 | 
						||
        }
 | 
						||
        else
 | 
						||
        {
 | 
						||
          //parse the next argument
 | 
						||
          checked_parse_arg(argc, argv, current, opt, name);
 | 
						||
        }
 | 
						||
      }
 | 
						||
 | 
						||
    }
 | 
						||
 | 
						||
    ++current;
 | 
						||
  }
 | 
						||
 | 
						||
  for (auto& opt : m_options)
 | 
						||
  {
 | 
						||
    auto& detail = opt.second;
 | 
						||
    const auto& value = detail->value();
 | 
						||
 | 
						||
    auto& store = m_parsed[detail->hash()];
 | 
						||
 | 
						||
    if(value.has_default() && !store.count() && !store.has_default()){
 | 
						||
      parse_default(detail);
 | 
						||
    }
 | 
						||
  }
 | 
						||
 | 
						||
  if (consume_remaining)
 | 
						||
  {
 | 
						||
    while (current < argc)
 | 
						||
    {
 | 
						||
      if (!consume_positional(argv[current], next_positional)) {
 | 
						||
        break;
 | 
						||
      }
 | 
						||
      ++current;
 | 
						||
    }
 | 
						||
 | 
						||
    //adjust argv for any that couldn't be swallowed
 | 
						||
    while (current != argc) {
 | 
						||
      unmatched.push_back(argv[current]);
 | 
						||
      ++current;
 | 
						||
    }
 | 
						||
  }
 | 
						||
 | 
						||
  finalise_aliases();
 | 
						||
 | 
						||
  ParseResult parsed(std::move(m_keys), std::move(m_parsed), std::move(m_sequential), std::move(unmatched));
 | 
						||
  return parsed;
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
void
 | 
						||
OptionParser::finalise_aliases()
 | 
						||
{
 | 
						||
  for (auto& option: m_options)
 | 
						||
  {
 | 
						||
    auto& detail = *option.second;
 | 
						||
    auto hash = detail.hash();
 | 
						||
    m_keys[detail.short_name()] = hash;
 | 
						||
    m_keys[detail.long_name()] = hash;
 | 
						||
 | 
						||
    m_parsed.emplace(hash, OptionValue());
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
void
 | 
						||
Options::add_option
 | 
						||
(
 | 
						||
  const std::string& group,
 | 
						||
  const Option& option
 | 
						||
)
 | 
						||
{
 | 
						||
    add_options(group, {option});
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
void
 | 
						||
Options::add_option
 | 
						||
(
 | 
						||
  const std::string& group,
 | 
						||
  const std::string& s,
 | 
						||
  const std::string& l,
 | 
						||
  std::string desc,
 | 
						||
  const 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.empty())
 | 
						||
  {
 | 
						||
    add_one_option(s, option);
 | 
						||
  }
 | 
						||
 | 
						||
  if (!l.empty())
 | 
						||
  {
 | 
						||
    add_one_option(l, option);
 | 
						||
  }
 | 
						||
 | 
						||
  m_option_list.push_front(*option.get());
 | 
						||
  auto iter = m_option_list.begin();
 | 
						||
  m_option_map[s] = iter;
 | 
						||
  m_option_map[l] = iter;
 | 
						||
 | 
						||
  //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,
 | 
						||
  const std::shared_ptr<OptionDetails>& details
 | 
						||
)
 | 
						||
{
 | 
						||
  auto in = m_options->emplace(option, details);
 | 
						||
 | 
						||
  if (!in.second)
 | 
						||
  {
 | 
						||
    throw_or_mimic<option_exists_error>(option);
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
String
 | 
						||
Options::help_one_group(const std::string& g) const
 | 
						||
{
 | 
						||
  using OptionHelp = std::vector<std::pair<String, String>>;
 | 
						||
 | 
						||
  auto group = m_help.find(g);
 | 
						||
  if (group == m_help.end())
 | 
						||
  {
 | 
						||
    return "";
 | 
						||
  }
 | 
						||
 | 
						||
  OptionHelp format;
 | 
						||
 | 
						||
  size_t longest = 0;
 | 
						||
 | 
						||
  String result;
 | 
						||
 | 
						||
  if (!g.empty())
 | 
						||
  {
 | 
						||
    result += toLocalString(" " + g + " options:\n");
 | 
						||
  }
 | 
						||
 | 
						||
  for (const auto& o : group->second.options)
 | 
						||
  {
 | 
						||
    if (m_positional_set.find(o.l) != m_positional_set.end() &&
 | 
						||
        !m_show_positional)
 | 
						||
    {
 | 
						||
      continue;
 | 
						||
    }
 | 
						||
 | 
						||
    auto s = format_option(o);
 | 
						||
    longest = (std::max)(longest, stringLength(s));
 | 
						||
    format.push_back(std::make_pair(s, String()));
 | 
						||
  }
 | 
						||
 | 
						||
  longest = (std::min)(longest, static_cast<size_t>(OPTION_LONGEST));
 | 
						||
 | 
						||
  //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;
 | 
						||
    }
 | 
						||
 | 
						||
    auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
 | 
						||
 | 
						||
    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';
 | 
						||
 | 
						||
    ++fiter;
 | 
						||
  }
 | 
						||
 | 
						||
  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)
 | 
						||
  {
 | 
						||
    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';
 | 
						||
    }
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
void
 | 
						||
Options::generate_all_groups_help(String& result) const
 | 
						||
{
 | 
						||
  std::vector<std::string> all_groups;
 | 
						||
  all_groups.reserve(m_help.size());
 | 
						||
 | 
						||
  for (const auto& group : m_help)
 | 
						||
  {
 | 
						||
    all_groups.push_back(group.first);
 | 
						||
  }
 | 
						||
 | 
						||
  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.empty() && !m_positional_help.empty()) {
 | 
						||
    result += " " + toLocalString(m_positional_help);
 | 
						||
  }
 | 
						||
 | 
						||
  result += "\n\n";
 | 
						||
 | 
						||
  if (help_groups.empty())
 | 
						||
  {
 | 
						||
    generate_all_groups_help(result);
 | 
						||
  }
 | 
						||
  else
 | 
						||
  {
 | 
						||
    generate_group_help(result, help_groups);
 | 
						||
  }
 | 
						||
 | 
						||
  return toUTF8String(result);
 | 
						||
}
 | 
						||
 | 
						||
inline
 | 
						||
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
 |