From 7811b18868f7d9a60eb7f23afd1cc4597e5ce989 Mon Sep 17 00:00:00 2001 From: Johannes Pohl Date: Tue, 26 Jun 2018 14:10:27 +0200 Subject: [PATCH 01/11] add xcode and clang --- .travis.yml | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 07b56ae..cb3b1fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,129 @@ language: cpp -compiler: - - gcc +dist: trusty +sudo: false + matrix: include: # build on ubuntu - os: linux - sudo: required addons: apt: + sources: + - ubuntu-toolchain-r-test packages: - - build-essential cmake + - g++-4.9 + env: + - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-5 + env: + - MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + env: + - MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" + + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-7 + env: + - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" + + # works on Precise and Trusty + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + packages: + - clang-3.6 + env: + - MATRIX_EVAL="CC=clang-3.6 && CXX=clang++-3.6" + + # works on Precise and Trusty + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + packages: + - clang-3.7 + env: + - MATRIX_EVAL="CC=clang-3.7 && CXX=clang++-3.7" + + # works on Precise and Trusty + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + packages: + - clang-3.8 + env: + - MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" + + # works on Trusty + - os: linux + addons: + apt: + sources: + - llvm-toolchain-trusty-3.9 + packages: + - clang-3.9 + env: + - MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9" + + # works on Trusty + - os: linux + addons: + apt: + sources: + - llvm-toolchain-trusty-4.0 + packages: + - clang-4.0 + env: + - MATRIX_EVAL="CC=clang-4.0 && CXX=clang++-4.0" + + # works on Trusty + - os: linux + addons: + apt: + sources: + - llvm-toolchain-trusty-5.0 + packages: + - clang-5.0 + env: + - MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0" + # build on osx + - os: osx + osx_image: xcode8 + - os: osx osx_image: xcode9.1 + before_install: - eval "${MATRIX_EVAL}" + script: - mkdir build - cd build From 157957ab8ce3d36077a8efc22fe53a50e1eeebf2 Mon Sep 17 00:00:00 2001 From: Pavel Kryukov Date: Tue, 11 Sep 2018 15:01:57 +0300 Subject: [PATCH 02/11] Add start_index argument to 'parse' function Usual case for emulation programs, like sde or gdb, is to pass first arguments to the emulator, and let the guest application handle latter arguments. To support this behavior, we introduce an option to choose index of the first argument to be handled by POPL. By default it is 1, as it is usually corresponds to the binary name. --- include/popl.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/popl.hpp b/include/popl.hpp index 8d8e27b..8e3a3c2 100644 --- a/include/popl.hpp +++ b/include/popl.hpp @@ -326,7 +326,8 @@ class OptionParser /// Parse the command line into the added Options /// @param argc command line argument count /// @param argv command line arguments - void parse(int argc, const char * const argv[]); + /// @param start_index index of starting argument + void parse(int argc, const char * const argv[], int start_index = 1); /// Produce a help message /// @param max_attribute show options up to this level (optional, advanced, expert) @@ -735,7 +736,7 @@ inline void Value::parse(OptionName what_name, const char* value) template -void Value::update_reference() +inline void Value::update_reference() { if (this->assign_to_) { @@ -916,14 +917,14 @@ inline std::shared_ptr OptionParser::get_option(char short_name) const } -inline void OptionParser::parse(int argc, const char * const argv[]) +inline void OptionParser::parse(int argc, const char * const argv[], int start_index) { unknown_options_.clear(); non_option_args_.clear(); for (auto& opt : options_) opt->clear(); - for (int n=1; n Date: Thu, 4 Oct 2018 10:42:08 +0200 Subject: [PATCH 03/11] Update README.md Replace Visibility with Attribute --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0818d4d..c76c0bb 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ std::string s; The variable `s` will carry the same value as `string_option.value()`, and thus the declaration of `string_option` can be omitted. -### Visibility of an option +### Attributes of an option Options have an `Attribute`: they can be hidden in the auto-created help message, or classified as "advanced", or "expert": @@ -91,7 +91,7 @@ auto advanced_int = op.add, Attribute::advanced>("i", "integer", "ad auto hidden_bool = op.add("", "hidden", "hidden flag"); ``` -Now `cout << op.help()` (same as `cout << op`) will not show the hidden or advanced option, while `cout << op.help(Visibility::advanced)` will show the advanced option. The hidden one is never shown to the user. +Now `cout << op.help()` (same as `cout << op`) will not show the hidden or advanced option, while `cout << op.help(Attribute::advanced)` will show the advanced option. The hidden one is never shown to the user. Also an option can be flagged as mandatory by assigning `Attribute::required` ## Example @@ -111,16 +111,16 @@ int main(int argc, char **argv) OptionParser op("Allowed options"); auto help_option = op.add("h", "help", "produce help message"); auto verbose_option = op.add("v", "verbose", "be verbose", &v); - auto hidden_option = op.add("x", "", "hidden option"); + auto hidden_option = op.add("x", "", "hidden option"); auto double_option = op.add>("d", "double", "test for double values", 3.14159265359); auto float_option = op.add>("f", "float", "test for float values", 2.71828182845f, &f); op.add>("i", "int", "test for int value w/o option", 23, &i); auto string_option = op.add>("s", "string", "test for string values"); auto implicit_int_option = op.add>("m", "implicit", "implicit test", 42); - auto advanced_option = op.add("", "advanced", "advanced option"); - auto expert_option = op.add("", "expert", "expert option"); + auto advanced_option = op.add("", "advanced", "advanced option"); + auto expert_option = op.add("", "expert", "expert option"); auto inactive_option = op.add("", "inactive", "inactive option"); - inactive_option->set_visibility(Visibility::inactive); + inactive_option->set_attribute(Attribute::inactive); implicit_int_option->assign_to(&m); op.parse(argc, argv); @@ -129,9 +129,9 @@ int main(int argc, char **argv) if (help_option->count() == 1) cout << op << "\n"; else if (help_option->count() == 2) - cout << op.help(Visibility::advanced) << "\n"; + cout << op.help(Attribute::advanced) << "\n"; else if (help_option->count() > 2) - cout << op.help(Visibility::expert) << "\n"; + cout << op.help(Attribute::expert) << "\n"; // show all non option arguments (those without "-o" or "--option") for (const auto& non_option_arg: op.non_option_args()) From 69640d8f0e18bb4c3d6c4e28e72e77e8be267ca4 Mon Sep 17 00:00:00 2001 From: badaix Date: Sun, 6 Oct 2019 21:01:02 +0200 Subject: [PATCH 04/11] add parsing of ini files --- .clang-format | 20 + CMakeLists.txt | 4 +- Makefile | 3 + include/popl.hpp | 1485 ++++++++++++++++++++++++---------------------- 4 files changed, 796 insertions(+), 716 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..7b1bec3 --- /dev/null +++ b/.clang-format @@ -0,0 +1,20 @@ +--- +AccessModifierOffset: '-4' +AllowShortBlocksOnASingleLine: 'false' +AllowShortCaseLabelsOnASingleLine: 'false' +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: 'false' +AllowShortLoopsOnASingleLine: 'false' +AlwaysBreakTemplateDeclarations: 'true' +BreakBeforeBraces: Allman +ColumnLimit: '160' +IndentCaseLabels: 'true' +IndentWidth: '4' +Language: Cpp +MaxEmptyLinesToKeep: '3' +PenaltyBreakComment: '100000' +PointerAlignment: Left +Standard: Cpp11 +UseTab: Never + +... diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d67f7a..2d4c85e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # (__) \__/(__) \____/ # This file is part of popl (program options parser lib) -# Copyright (C) 2015-2018 Johannes Pohl +# Copyright (C) 2015-2019 Johannes Pohl # This software may be modified and distributed under the terms # of the MIT license. See the LICENSE file for details. @@ -18,7 +18,7 @@ if (CMAKE_VERSION VERSION_LESS "3.1") else () set (CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_EXTENSIONS OFF) - set(PROJECT_VERSION "1.2.0") + set(PROJECT_VERSION "1.2.90") endif () diff --git a/Makefile b/Makefile index de31efb..5d04977 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,9 @@ BIN = popl_example all: $(TARGET) +reformat: + clang-format -i include/popl.hpp + $(TARGET): $(OBJ) $(CXX) $(CXXFLAGS) -o $(BIN) $(OBJ) $(LDFLAGS) strip $(BIN) diff --git a/include/popl.hpp b/include/popl.hpp index fad23b4..6b91e78 100644 --- a/include/popl.hpp +++ b/include/popl.hpp @@ -1,20 +1,21 @@ /*** - ____ __ ____ __ - ( _ \ / \( _ \( ) + ____ __ ____ __ + ( _ \ / \( _ \( ) ) __/( O )) __// (_/\ (__) \__/(__) \____/ - version 1.2.0 + version 1.2.90 https://github.com/badaix/popl This file is part of popl (program options parser lib) - Copyright (C) 2015-2018 Johannes Pohl - + Copyright (C) 2015-2019 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' +/// 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 @@ -26,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +38,7 @@ namespace popl { -#define POPL_VERSION "1.2.0" +#define POPL_VERSION "1.2.90" /// Option's argument type @@ -47,9 +49,9 @@ namespace popl */ enum class Argument { - no = 0, // option never takes an argument - required, // option always requires an argument - optional // option may take an argument + no = 0, // option never takes an argument + required, // option always requires an argument + optional // option may take an argument }; @@ -64,12 +66,12 @@ enum class Argument */ enum class Attribute { - inactive = 0, - hidden = 1, - required = 2, - optional = 3, - advanced = 4, - expert = 5 + inactive = 0, + hidden = 1, + required = 2, + optional = 3, + advanced = 4, + expert = 5 }; @@ -81,9 +83,9 @@ enum class Attribute */ enum class OptionName { - unspecified, - short_name, - long_name + unspecified, + short_name, + long_name }; @@ -95,159 +97,165 @@ enum class OptionName */ class Option { -friend class OptionParser; + 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); + /// 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; - /// Destructor - virtual ~Option() = default; + /// default copy constructor + Option(const Option&) = default; - /// default copy constructor - Option(const Option&) = default; + /// default move constructor + Option(Option&&) = default; - /// default move constructor - Option(Option&&) = default; + /// default assignement operator + Option& operator=(const Option&) = default; - /// default assignement operator - Option& operator=(const Option&) = default; + /// default move assignement operator + Option& operator=(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 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 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 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 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; - /// 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); - /// 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 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; - /// 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 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; - /// 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_; + /// 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 +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; - - /// 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; + /// 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_; + 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; + virtual void update_reference(); + virtual void add_value(const T& value); + void clear() override; - T* assign_to_; - std::vector values_; + T* assign_to_; + std::vector values_; }; - /// Value option with implicit default value /** * Value option with implicit default value @@ -255,21 +263,20 @@ class Value : public Option * -without argument it carries the implicit default value * -with argument it carries the explicit value */ -template +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); + 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; + Argument argument_type() const override; protected: - void parse(OptionName what_name, const char* value) override; + void parse(OptionName what_name, const char* value) override; }; - /// Value option without value /** * Value option without value @@ -279,100 +286,102 @@ class Implicit : public Value class Switch : public Value { public: - Switch(const std::string& short_name, const std::string& long_name, const std::string& description, bool* assign_to = nullptr); + 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; + void set_default(const bool& value) = delete; + Argument argument_type() const override; protected: - void parse(OptionName what_name, const char* value) override; + void parse(OptionName what_name, const char* value) override; }; - using Option_ptr = std::shared_ptr