/*** ____ __ ____ __ ( _ \ / \( _ \( ) ) __/( O )) __// (_/\ (__) \__/(__) \____/ version 1.3.0 https://github.com/badaix/popl This file is part of popl (program options parser lib) Copyright (C) 2015-2021 Johannes Pohl This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. ***/ /// checked with clang-tidy: /// run-clang-tidy-3.8.py -header-filter='.*' /// -checks='*,-misc-definitions-in-headers,-google-readability-braces-around-statements,-readability-braces-around-statements,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-google-build-using-namespace,-google-build-using-namespace' #ifndef POPL_HPP #define POPL_HPP #ifndef NOMINMAX #define NOMINMAX #endif // NOMINMAX #include #include #include #include #include #include #include #include #include #ifdef WINDOWS #include #endif namespace popl { #define POPL_VERSION "1.3.0" /// Option's argument type /** * Switch has "no" argument * Value has "required" argument * Implicit has "optional" argument */ enum class Argument { no = 0, // option never takes an argument required, // option always requires an argument optional // option may take an argument }; /// Option's attribute /** * inactive: Option is not set and will not be parsed * hidden: Option is active, but will not show up in the help message * required: Option must be set on the command line. Otherwise an exception will be thrown * optional: Option must not be set. Default attribute. * advanced: Option is advanced and will only show up in the advanced help message * expoert: Option is expert and will only show up in the expert help message */ enum class Attribute { inactive = 0, hidden = 1, required = 2, optional = 3, advanced = 4, expert = 5 }; /// Option name type. Used in invalid_option exception. /** * unspecified: not specified * short_name: The option's short name * long_name: The option's long name */ enum class OptionName { unspecified, short_name, long_name }; /// Abstract Base class for Options /** * Base class for Options * holds just configuration data, no runtime data. * Option is not bound to a special type "T" */ class Option { friend class OptionParser; public: /// Construct an Option /// @param short_name the options's short name. Must be empty or one character. /// @param long_name the option's long name. Can be empty. /// @param description the Option's description that will be shown in the help message Option(const std::string& short_name, const std::string& long_name, std::string description); /// Destructor virtual ~Option() = default; /// default copy constructor Option(const Option&) = default; /// default move constructor Option(Option&&) = default; /// default assignement operator Option& operator=(const Option&) = default; /// default move assignement operator Option& operator=(Option&&) = default; /// Get the Option's short name /// @return character of the options's short name or 0 if no short name is defined char short_name() const; /// Get the Option's long name /// @return the long name of the Option. Empty string if no long name is defined std::string long_name() const; /// Get the Option's long or short name /// @param what_name the option's name to return /// @param what_hyphen preced the returned name with (double-)hypen /// @return the requested name of the Option. Empty string if not defined. std::string name(OptionName what_name, bool with_hypen = false) const; /// Get the Option's description /// @return the description std::string description() const; /// Get the Option's default value /// @param out stream to write the default value to /// @return true if a default value is available, false if not virtual bool get_default(std::ostream& out) const = 0; /// Set the Option's attribute /// @param attribute void set_attribute(const Attribute& attribute); /// Get the Option's attribute /// @return the Options's attribute Attribute attribute() const; /// Get the Option's argument type /// @return argument type (no, required, optional) virtual Argument argument_type() const = 0; /// Check how often the Option is set on command line /// @return the Option's count on command line virtual size_t count() const = 0; /// Check if the Option is set /// @return true if set at least once virtual bool is_set() const = 0; protected: /// Parse the command line option and fill the internal data structure /// @param what_name short or long option name /// @param value the value as given on command line virtual void parse(OptionName what_name, const char* value) = 0; /// Clear the internal data structure virtual void clear() = 0; std::string short_name_; std::string long_name_; std::string description_; Attribute attribute_; }; /// Value option with optional default value /** * Value option with optional default value * If set, it requires an argument */ template class Value : public Option { public: /// Construct an Value Option /// @param short_name the option's short name. Must be empty or one character. /// @param long_name the option's long name. Can be empty. /// @param description the Option's description that will be shown in the help message Value(const std::string& short_name, const std::string& long_name, const std::string& description); /// Construct an Value Option /// @param short_name the option's short name. Must be empty or one character. /// @param long_name the option's long name. Can be empty. /// @param description the Option's description that will be shown in the help message /// @param default_val the Option's default value /// @param assign_to pointer to a variable to assign the parsed command line value to Value(const std::string& short_name, const std::string& long_name, const std::string& description, const T& default_val, T* assign_to = nullptr); size_t count() const override; bool is_set() const override; /// Assign the last parsed command line value to "var" /// @param var pointer to the variable where is value is written to void assign_to(T* var); /// Manually set the Option's value. Deletes current value(s) /// @param value the new value of the option void set_value(const T& value); /// Get the Option's value. Will throw if option at index idx is not available /// @param idx the zero based index of the value (if set multiple times) /// @return the Option's value at index "idx" T value(size_t idx = 0) const; /// Get the Option's value, return default_value if not set. /// @param default_value return value if value is not set /// @param idx the zero based index of the value (if set multiple times) /// @return the Option's value at index "idx" or the default value or default_value T value_or(const T& default_value, size_t idx = 0) const; /// Set the Option's default value /// @param value the default value if not specified on command line void set_default(const T& value); /// Check if the Option has a default value /// @return true if the Option has a default value bool has_default() const; /// Get the Option's default value. Will throw if no default is set. /// @return the Option's default value T get_default() const; bool get_default(std::ostream& out) const override; Argument argument_type() const override; protected: void parse(OptionName what_name, const char* value) override; std::unique_ptr default_; virtual void update_reference(); virtual void add_value(const T& value); void clear() override; T* assign_to_; std::vector values_; }; /// Value option with implicit default value /** * Value option with implicit default value * If set, an argument is optional * -without argument it carries the implicit default value * -with argument it carries the explicit value */ template class Implicit : public Value { public: Implicit(const std::string& short_name, const std::string& long_name, const std::string& description, const T& implicit_val, T* assign_to = nullptr); Argument argument_type() const override; protected: void parse(OptionName what_name, const char* value) override; }; /// Value option without value /** * Value option without value * Does not require an argument * Can be either set or not set */ class Switch : public Value { public: Switch(const std::string& short_name, const std::string& long_name, const std::string& description, bool* assign_to = nullptr); void set_default(const bool& value) = delete; Argument argument_type() const override; protected: void parse(OptionName what_name, const char* value) override; }; using Option_ptr = std::shared_ptr