Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package gebaar-libinput for openSUSE:Factory
checked in at 2021-06-19 23:03:14
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/gebaar-libinput (Old)
and /work/SRC/openSUSE:Factory/.gebaar-libinput.new.2625 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "gebaar-libinput"
Sat Jun 19 23:03:14 2021 rev:2 rq:900729 version:0.0.5
Changes:
--------
--- /work/SRC/openSUSE:Factory/gebaar-libinput/gebaar-libinput.changes
2019-04-30 12:58:29.234132690 +0200
+++
/work/SRC/openSUSE:Factory/.gebaar-libinput.new.2625/gebaar-libinput.changes
2021-06-19 23:03:44.291735884 +0200
@@ -1,0 +2,7 @@
+Mon May 31 20:17:53 UTC 2021 - Christophe Giboudeaux <[email protected]>
+
+- Add Patch to fix build with GCC 11:
+ * 0001-g-11-requires-limits-header.patch
+- Update cxxopts to 2.1.2
+
+-------------------------------------------------------------------
Old:
----
cxxopts-2.1.2.tar.gz
New:
----
0001-g-11-requires-limits-header.patch
cxxopts-2.2.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ gebaar-libinput.spec ++++++
--- /var/tmp/diff_new_pack.2tpM5j/_old 2021-06-19 23:03:44.703736519 +0200
+++ /var/tmp/diff_new_pack.2tpM5j/_new 2021-06-19 23:03:44.707736526 +0200
@@ -17,7 +17,7 @@
%define cpptoml 0.1.1
-%define cxxopts 2.1.2
+%define cxxopts 2.2.1
Name: gebaar-libinput
Version: 0.0.5
Release: 0
@@ -29,6 +29,8 @@
Source1:
https://github.com/skystrife/cpptoml/archive/v%{cpptoml}.tar.gz#/cpptoml-%{cpptoml}.tar.gz
Source2:
https://github.com/jarro2783/cxxopts/archive/v%{cxxopts}.tar.gz#/cxxopts-%{cxxopts}.tar.gz
Patch0: cmake-version.patch
+# PATCH-FIX-UPSTREAM https://github.com/skystrife/cpptoml/pull/123
+Patch1: 0001-g-11-requires-limits-header.patch
BuildRequires: cmake
%if 0%{?suse_version} == 1500
BuildRequires: gcc8
@@ -53,6 +55,7 @@
%patch0
tar -xzf %{SOURCE1} -C libs/cpptoml --strip-components=1
tar -xzf %{SOURCE2} -C libs/cxxopts --strip-components=1
+%patch1 -p1
%build
%if 0%{?suse_version} == 1500
++++++ 0001-g-11-requires-limits-header.patch ++++++
>From 02e34e3a7ae81b0209f131623d978cce9a49e6a7 Mon Sep 17 00:00:00 2001
From: Dirk Eddelbuettel <[email protected]>
Date: Mon, 30 Nov 2020 09:41:49 -0600
Subject: [PATCH] g++-11 requires limits header
---
libs/cpptoml/include/cpptoml.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/libs/cpptoml/include/cpptoml.h b/libs/cpptoml/include/cpptoml.h
index 5a00da3..1dc9fd1 100644
--- a/libs/cpptoml/include/cpptoml.h
+++ b/libs/cpptoml/include/cpptoml.h
@@ -14,6 +14,7 @@
#include <cstring>
#include <fstream>
#include <iomanip>
+#include <limits>
#include <map>
#include <memory>
#include <sstream>
--
2.31.1
++++++ cxxopts-2.1.2.tar.gz -> cxxopts-2.2.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cxxopts-2.1.2/CHANGELOG.md
new/cxxopts-2.2.1/CHANGELOG.md
--- old/cxxopts-2.1.2/CHANGELOG.md 2019-01-13 22:12:07.000000000 +0100
+++ new/cxxopts-2.2.1/CHANGELOG.md 2020-08-04 00:59:54.000000000 +0200
@@ -3,11 +3,42 @@
This is the changelog for `cxxopts`, a C++11 library for parsing command line
options. The project adheres to semantic versioning.
-## 2.1.2
+## 2.2.1
+
+### Changed
+
+* Only search for a C++ compiler in CMakeLists.txt.
+* Allow installing to be disabled.
+
+### Bug Fixes
+
+* Fix error printing long help lines.
+* Fix duplicate default options when there is a short and long option.
+
+## 2.2
+
+### Changed
+
+* Allow integers to have leading zeroes.
+* Build the tests by default.
+* Don't check for container when showing positional help.
+
+### Added
+
+* Iterator inputs to `parse_positional`.
+* Throw an exception if the option in `parse_positional` doesn't exist.
+* Parse a delimited list in a single argument for vector options.
+* Add an option to disable implicit value on booleans.
### Bug Fixes
-* Use `std::forward` instead of returning a copy in `toLocalString`.
+* Fix a warning about possible loss of data.
+* Fix version numbering in CMakeLists.txt
+* Remove unused declaration of the undefined `ParseResult::get_option`.
+* Throw on invalid option syntax when beginning with a `-`.
+* Throw in `as` when option wasn't present.
+* Fix catching exceptions by reference.
+* Fix out of bounds errors parsing integers.
## 2.1.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cxxopts-2.1.2/CMakeLists.txt
new/cxxopts-2.2.1/CMakeLists.txt
--- old/cxxopts-2.1.2/CMakeLists.txt 2019-01-13 22:12:07.000000000 +0100
+++ new/cxxopts-2.2.1/CMakeLists.txt 2020-08-04 00:59:54.000000000 +0200
@@ -18,14 +18,25 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
cmake_minimum_required(VERSION 3.1)
-project(cxxopts)
-enable_testing()
+# parse the current version from the cxxopts header
+file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/cxxopts.hpp"
cxxopts_version_defines
+ REGEX "#define CXXOPTS__VERSION_(MAJOR|MINOR|PATCH)")
+foreach(ver ${cxxopts_version_defines})
+ if(ver MATCHES "#define CXXOPTS__VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$")
+ set(CXXOPTS__VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE
INTERNAL "")
+ endif()
+endforeach()
+set(VERSION
${CXXOPTS__VERSION_MAJOR}.${CXXOPTS__VERSION_MINOR}.${CXXOPTS__VERSION_PATCH})
+message(STATUS "cxxopts version ${VERSION}")
+
+project(cxxopts VERSION "${VERSION}" LANGUAGES CXX)
-set(VERSION "2.1.2")
+enable_testing()
option(CXXOPTS_BUILD_EXAMPLES "Set to ON to build examples" ON)
-option(CXXOPTS_BUILD_TESTS "Set to ON to build tests" OFF)
+option(CXXOPTS_BUILD_TESTS "Set to ON to build tests" ON)
+option(CXXOPTS_ENABLE_INSTALL "Generate the install target" ON)
# request c++11 without gnu extension for the whole project and enable more
warnings
if (CXXOPTS_CXX_STANDARD)
@@ -60,35 +71,37 @@
$<INSTALL_INTERFACE:include>
)
-include(CMakePackageConfigHelpers)
-set(CXXOPTS_CMAKE_DIR "lib/cmake/cxxopts" CACHE STRING
- "Installation directory for cmake files, relative to
${CMAKE_INSTALL_PREFIX}.")
-set(version_config "${PROJECT_BINARY_DIR}/cxxopts-config-version.cmake")
-set(project_config "${PROJECT_BINARY_DIR}/cxxopts-config.cmake")
-set(targets_export_name cxxopts-targets)
-
-# Generate the version, config and target files into the build directory.
-write_basic_package_version_file(
- ${version_config}
- VERSION ${VERSION}
- COMPATIBILITY AnyNewerVersion)
-configure_package_config_file(
- ${PROJECT_SOURCE_DIR}/cxxopts-config.cmake.in
- ${project_config}
- INSTALL_DESTINATION ${CXXOPTS_CMAKE_DIR})
-export(TARGETS cxxopts NAMESPACE cxxopts::
- FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
-
-# Install version, config and target files.
-install(
- FILES ${project_config} ${version_config}
- DESTINATION ${CXXOPTS_CMAKE_DIR})
-install(EXPORT ${targets_export_name} DESTINATION ${CXXOPTS_CMAKE_DIR}
- NAMESPACE cxxopts::)
-
-# Install the header file and export the target
-install(TARGETS cxxopts EXPORT ${targets_export_name} DESTINATION lib)
-install(FILES ${PROJECT_SOURCE_DIR}/include/cxxopts.hpp DESTINATION include)
+if(CXXOPTS_ENABLE_INSTALL)
+ include(CMakePackageConfigHelpers)
+ set(CXXOPTS_CMAKE_DIR "lib/cmake/cxxopts" CACHE STRING
+ "Installation directory for cmake files, relative to
${CMAKE_INSTALL_PREFIX}.")
+ set(version_config "${PROJECT_BINARY_DIR}/cxxopts-config-version.cmake")
+ set(project_config "${PROJECT_BINARY_DIR}/cxxopts-config.cmake")
+ set(targets_export_name cxxopts-targets)
+
+ # Generate the version, config and target files into the build directory.
+ write_basic_package_version_file(
+ ${version_config}
+ VERSION ${VERSION}
+ COMPATIBILITY AnyNewerVersion)
+ configure_package_config_file(
+ ${PROJECT_SOURCE_DIR}/cxxopts-config.cmake.in
+ ${project_config}
+ INSTALL_DESTINATION ${CXXOPTS_CMAKE_DIR})
+ export(TARGETS cxxopts NAMESPACE cxxopts::
+ FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
+
+ # Install version, config and target files.
+ install(
+ FILES ${project_config} ${version_config}
+ DESTINATION ${CXXOPTS_CMAKE_DIR})
+ install(EXPORT ${targets_export_name} DESTINATION ${CXXOPTS_CMAKE_DIR}
+ NAMESPACE cxxopts::)
+
+ # Install the header file and export the target
+ install(TARGETS cxxopts EXPORT ${targets_export_name} DESTINATION lib)
+ install(FILES ${PROJECT_SOURCE_DIR}/include/cxxopts.hpp DESTINATION
include)
+endif()
add_subdirectory(src)
add_subdirectory(test)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cxxopts-2.1.2/INSTALL new/cxxopts-2.2.1/INSTALL
--- old/cxxopts-2.1.2/INSTALL 2019-01-13 22:12:07.000000000 +0100
+++ new/cxxopts-2.2.1/INSTALL 2020-08-04 00:59:54.000000000 +0200
@@ -1,10 +1,23 @@
-It is preferable to build out of source.
+== System installation ==
-cmake ${CXXOPTS_DIR}
-make
+This library is header only. So you can either copy `include/cxxopts.hpp` to
`/usr/include` or `/usr/local/include`, or add `include` to your search path.
+== Building the examples and tests ==
+
+It is preferable to build out of source. Make a build directory somewhere, and
then
+do the following, where `${CXXOPTS_DIR}` is the path that you checked out
`cxxopts`
+to:
+
+ cmake ${CXXOPTS_DIR}
+ make
You can use another build tool, such as ninja.
-cmake -G Ninja ${CXXOPTS_DIR}
-ninja
+ cmake -G Ninja ${CXXOPTS_DIR}
+ ninja
+
+
+To run the tests, you have to configure `cxxopts` with another flag:
+ cmake -D CXXOPTS_BUILD_TESTS=On ${CXXOPTS_DIR}
+ make
+ make test
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cxxopts-2.1.2/README.md new/cxxopts-2.2.1/README.md
--- old/cxxopts-2.1.2/README.md 2019-01-13 22:12:07.000000000 +0100
+++ new/cxxopts-2.2.1/README.md 2020-08-04 00:59:54.000000000 +0200
@@ -111,8 +111,22 @@
Boolean options have a default implicit value of `"true"`, which can be
overridden. The effect is that writing `-o` by itself will set option `o` to
-`true`. However, they can also be written with various strings using either
-`=value` or the next argument.
+`true`. However, they can also be written with various strings using `=value`.
+There is no way to disambiguate positional arguments from the value following
+a boolean, so we have chosen that they will be positional arguments, and
+therefore, `-o false` does not work.
+
+## `std::vector<T>` values
+
+Parsing of list of values in form of an `std::vector<T>` is also supported, as
long as `T`
+can be parsed. To separate single values in a list the definition
`CXXOPTS_VECTOR_DELIMITER`
+is used, which is ',' by default. Ensure that you use no whitespaces between
values because
+those would be interpreted as the next command line option. Example for a
command line option
+that can be parsed as a `std::vector<double>`:
+
+~~~
+--my_list=1,-2.1,3,4.5
+~~~
## Custom help
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cxxopts-2.1.2/include/cxxopts.hpp
new/cxxopts-2.2.1/include/cxxopts.hpp
--- old/cxxopts-2.1.2/include/cxxopts.hpp 2019-01-13 22:12:07.000000000
+0100
+++ new/cxxopts-2.2.1/include/cxxopts.hpp 2020-08-04 00:59:54.000000000
+0200
@@ -29,6 +29,7 @@
#include <cctype>
#include <exception>
#include <iostream>
+#include <limits>
#include <map>
#include <memory>
#include <regex>
@@ -43,11 +44,23 @@
#define CXXOPTS_HAS_OPTIONAL
#endif
+#ifndef CXXOPTS_VECTOR_DELIMITER
+#define CXXOPTS_VECTOR_DELIMITER ','
+#endif
+
+#define CXXOPTS__VERSION_MAJOR 2
+#define CXXOPTS__VERSION_MINOR 2
+#define CXXOPTS__VERSION_PATCH 0
+
namespace cxxopts
{
static constexpr struct {
uint8_t major, minor, patch;
- } version = {2, 1, 2};
+ } version = {
+ CXXOPTS__VERSION_MAJOR,
+ CXXOPTS__VERSION_MINOR,
+ CXXOPTS__VERSION_PATCH
+ };
}
//when we ask cxxopts to use Unicode, help strings are processed using ICU,
@@ -301,6 +314,9 @@
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;
};
@@ -346,7 +362,7 @@
{
public:
option_exists_error(const std::string& option)
- : OptionSpecException(u8"Option " + LQUOTE + option + RQUOTE + u8" already
exists")
+ : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already
exists")
{
}
};
@@ -355,7 +371,16 @@
{
public:
invalid_option_format_error(const std::string& format)
- : OptionSpecException(u8"Invalid option format " + LQUOTE + format +
RQUOTE)
+ : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE)
+ {
+ }
+ };
+
+ class option_syntax_exception : public OptionParseException {
+ public:
+ option_syntax_exception(const std::string& text)
+ : OptionParseException("Argument " + LQUOTE + text + RQUOTE +
+ " starts with a - but has incorrect syntax")
{
}
};
@@ -364,7 +389,7 @@
{
public:
option_not_exists_exception(const std::string& option)
- : OptionParseException(u8"Option " + LQUOTE + option + RQUOTE + u8" does
not exist")
+ : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not
exist")
{
}
};
@@ -374,7 +399,7 @@
public:
missing_argument_exception(const std::string& option)
: OptionParseException(
- u8"Option " + LQUOTE + option + RQUOTE + u8" is missing an argument"
+ "Option " + LQUOTE + option + RQUOTE + " is missing an argument"
)
{
}
@@ -385,7 +410,7 @@
public:
option_requires_argument_exception(const std::string& option)
: OptionParseException(
- u8"Option " + LQUOTE + option + RQUOTE + u8" requires an argument"
+ "Option " + LQUOTE + option + RQUOTE + " requires an argument"
)
{
}
@@ -400,8 +425,8 @@
const std::string& arg
)
: OptionParseException(
- u8"Option " + LQUOTE + option + RQUOTE +
- u8" does not take an argument, but argument " +
+ "Option " + LQUOTE + option + RQUOTE +
+ " does not take an argument, but argument " +
LQUOTE + arg + RQUOTE + " given"
)
{
@@ -412,7 +437,7 @@
{
public:
option_not_present_exception(const std::string& option)
- : OptionParseException(u8"Option " + LQUOTE + option + RQUOTE + u8" not
present")
+ : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not
present")
{
}
};
@@ -425,7 +450,7 @@
const std::string& arg
)
: OptionParseException(
- u8"Argument " + LQUOTE + arg + RQUOTE + u8" failed to parse"
+ "Argument " + LQUOTE + arg + RQUOTE + " failed to parse"
)
{
}
@@ -436,7 +461,7 @@
public:
option_required_exception(const std::string& option)
: OptionParseException(
- u8"Option " + LQUOTE + option + RQUOTE + u8" is required but not
present"
+ "Option " + LQUOTE + option + RQUOTE + " is required but not present"
)
{
}
@@ -447,11 +472,11 @@
namespace
{
std::basic_regex<char> integer_pattern
- ("(-)?(0x)?([1-9a-zA-Z][0-9a-zA-Z]*)|((0x)?0)");
+ ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
std::basic_regex<char> truthy_pattern
- ("(t|T)(rue)?");
+ ("(t|T)(rue)?|1");
std::basic_regex<char> falsy_pattern
- ("((f|F)(alse)?)?");
+ ("(f|F)(alse)?|0");
}
namespace detail
@@ -468,14 +493,14 @@
{
if (negative)
{
- if (u > static_cast<U>(-std::numeric_limits<T>::min()))
+ if (u > static_cast<U>((std::numeric_limits<T>::min)()))
{
throw argument_incorrect_type(text);
}
}
else
{
- if (u > static_cast<U>(std::numeric_limits<T>::max()))
+ if (u > static_cast<U>((std::numeric_limits<T>::max)()))
{
throw argument_incorrect_type(text);
}
@@ -506,7 +531,7 @@
// if we got to here, then `t` is a positive number that fits into
// `R`. So to avoid MSVC C4146, we first cast it to `R`.
// See https://github.com/jarro2783/cxxopts/issues/62 for more details.
- return -static_cast<R>(t);
+ return -static_cast<R>(t-1)-1;
}
template <typename R, typename T>
@@ -536,7 +561,6 @@
using US = typename std::make_unsigned<T>::type;
- constexpr auto umax = std::numeric_limits<US>::max();
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;
@@ -547,31 +571,32 @@
for (auto iter = value_match.first; iter != value_match.second; ++iter)
{
- size_t digit = 0;
+ US digit = 0;
if (*iter >= '0' && *iter <= '9')
{
- digit = *iter - '0';
+ digit = static_cast<US>(*iter - '0');
}
else if (base == 16 && *iter >= 'a' && *iter <= 'f')
{
- digit = *iter - 'a' + 10;
+ digit = static_cast<US>(*iter - 'a' + 10);
}
else if (base == 16 && *iter >= 'A' && *iter <= 'F')
{
- digit = *iter - 'A' + 10;
+ digit = static_cast<US>(*iter - 'A' + 10);
}
else
{
throw argument_incorrect_type(text);
}
- if (umax - digit < result * base)
+ US next = result * base + digit;
+ if (result > next)
{
throw argument_incorrect_type(text);
}
- result = result * base + digit;
+ result = next;
}
detail::check_signed_range<T>(negative, result, text);
@@ -584,7 +609,7 @@
}
else
{
- value = result;
+ value = static_cast<T>(result);
}
}
@@ -697,9 +722,13 @@
void
parse_value(const std::string& text, std::vector<T>& value)
{
- T v;
- parse_value(text, v);
- value.push_back(v);
+ std::stringstream in(text);
+ std::string token;
+ while(in.eof() == false && std::getline(in, token,
CXXOPTS_VECTOR_DELIMITER)) {
+ T v;
+ parse_value(token, v);
+ value.emplace_back(std::move(v));
+ }
}
#ifdef CXXOPTS_HAS_OPTIONAL
@@ -808,6 +837,13 @@
return shared_from_this();
}
+ std::shared_ptr<Value>
+ no_implicit_value()
+ {
+ m_implicit = false;
+ return shared_from_this();
+ }
+
std::string
get_default_value() const
{
@@ -1018,19 +1054,31 @@
parse_default(std::shared_ptr<const OptionDetails> details)
{
ensure_value(details);
+ m_default = true;
m_value->parse();
}
size_t
- count() const
+ count() const noexcept
{
return m_count;
}
+ // TODO: maybe default options should count towards the number of arguments
+ bool
+ has_default() const noexcept
+ {
+ return m_default;
+ }
+
template <typename T>
const T&
as() const
{
+ if (m_value == nullptr) {
+ throw std::domain_error("No value");
+ }
+
#ifdef CXXOPTS_NO_RTTI
return static_cast<const values::standard_value<T>&>(*m_value).get();
#else
@@ -1050,6 +1098,7 @@
std::shared_ptr<Value> m_value;
size_t m_count = 0;
+ bool m_default = false;
};
class KeyValue
@@ -1068,7 +1117,8 @@
return m_key;
}
- const std::string
+ const
+ std::string&
value() const
{
return m_value;
@@ -1093,15 +1143,18 @@
public:
ParseResult(
- const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>&,
+ const std::shared_ptr<
+ std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
+ >,
std::vector<std::string>,
+ bool allow_unrecognised,
int&, char**&);
size_t
count(const std::string& o) const
{
- auto iter = m_options.find(o);
- if (iter == m_options.end())
+ auto iter = m_options->find(o);
+ if (iter == m_options->end())
{
return 0;
}
@@ -1114,9 +1167,9 @@
const OptionValue&
operator[](const std::string& option) const
{
- auto iter = m_options.find(option);
+ auto iter = m_options->find(option);
- if (iter == m_options.end())
+ if (iter == m_options->end())
{
throw option_not_present_exception(option);
}
@@ -1134,9 +1187,6 @@
private:
- OptionValue&
- get_option(std::shared_ptr<OptionDetails>);
-
void
parse(int& argc, char**& argv);
@@ -1167,18 +1217,23 @@
const std::string& name
);
- const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
- &m_options;
+ const std::shared_ptr<
+ std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
+ > m_options;
std::vector<std::string> m_positional;
std::vector<std::string>::iterator m_next_positional;
std::unordered_set<std::string> m_positional_set;
std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results;
+ bool m_allow_unrecognised;
+
std::vector<KeyValue> m_sequential;
};
class Options
{
+ typedef std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
+ OptionMap;
public:
Options(std::string program, std::string help_string = "")
@@ -1187,6 +1242,8 @@
, m_custom_help("[OPTION...]")
, m_positional_help("positional parameters")
, m_show_positional(false)
+ , m_allow_unrecognised(false)
+ , m_options(std::make_shared<OptionMap>())
, m_next_positional(m_positional.end())
{
}
@@ -1212,6 +1269,13 @@
return *this;
}
+ Options&
+ allow_unrecognised_options()
+ {
+ m_allow_unrecognised = true;
+ return *this;
+ }
+
ParseResult
parse(int& argc, char**& argv);
@@ -1239,8 +1303,14 @@
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;
+ help(const std::vector<std::string>& groups = {}) const;
const std::vector<std::string>
groups() const;
@@ -1275,8 +1345,9 @@
std::string m_custom_help;
std::string m_positional_help;
bool m_show_positional;
+ bool m_allow_unrecognised;
- std::unordered_map<std::string, std::shared_ptr<OptionDetails>> m_options;
+ std::shared_ptr<OptionMap> m_options;
std::vector<std::string> m_positional;
std::vector<std::string>::iterator m_next_positional;
std::unordered_set<std::string> m_positional_set;
@@ -1392,7 +1463,12 @@
lastSpace = current;
}
- if (size > width)
+ if (*current == '\n')
+ {
+ startLine = current + 1;
+ lastSpace = startLine;
+ }
+ else if (size > width)
{
if (lastSpace == startLine)
{
@@ -1408,6 +1484,7 @@
stringAppend(result, "\n");
stringAppend(result, start, ' ');
startLine = lastSpace + 1;
+ lastSpace = startLine;
}
size = 0;
}
@@ -1429,13 +1506,17 @@
inline
ParseResult::ParseResult
(
- const std::unordered_map<std::string, std::shared_ptr<OptionDetails>>&
options,
+ const std::shared_ptr<
+ std::unordered_map<std::string, std::shared_ptr<OptionDetails>>
+ > options,
std::vector<std::string> positional,
+ bool allow_unrecognised,
int& argc, char**& argv
)
: m_options(options)
, m_positional(std::move(positional))
, m_next_positional(m_positional.begin())
+, m_allow_unrecognised(allow_unrecognised)
{
parse(argc, argv);
}
@@ -1567,9 +1648,9 @@
void
ParseResult::add_to_option(const std::string& option, const std::string& arg)
{
- auto iter = m_options.find(option);
+ auto iter = m_options->find(option);
- if (iter == m_options.end())
+ if (iter == m_options->end())
{
throw option_not_exists_exception(option);
}
@@ -1583,8 +1664,8 @@
{
while (m_next_positional != m_positional.end())
{
- auto iter = m_options.find(*m_next_positional);
- if (iter != m_options.end())
+ auto iter = m_options->find(*m_next_positional);
+ if (iter != m_options->end())
{
auto& result = m_results[iter->second];
if (!iter->second->value().is_container())
@@ -1607,7 +1688,10 @@
return true;
}
}
- ++m_next_positional;
+ else
+ {
+ throw option_not_exists_exception(*m_next_positional);
+ }
}
return false;
@@ -1641,7 +1725,7 @@
ParseResult
Options::parse(int& argc, char**& argv)
{
- ParseResult result(m_options, m_positional, argc, argv);
+ ParseResult result(m_options, m_positional, m_allow_unrecognised, argc,
argv);
return result;
}
@@ -1671,6 +1755,13 @@
{
//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 option_syntax_exception(argv[current]);
+ }
+ }
+
//if true is returned here then it was consumed, otherwise it is
//ignored
if (consume_positional(argv[current]))
@@ -1693,11 +1784,19 @@
for (std::size_t i = 0; i != s.size(); ++i)
{
std::string name(1, s[i]);
- auto iter = m_options.find(name);
+ auto iter = m_options->find(name);
- if (iter == m_options.end())
+ if (iter == m_options->end())
{
- throw option_not_exists_exception(name);
+ if (m_allow_unrecognised)
+ {
+ continue;
+ }
+ else
+ {
+ //error
+ throw option_not_exists_exception(name);
+ }
}
auto value = iter->second;
@@ -1722,11 +1821,23 @@
{
const std::string& name = result[1];
- auto iter = m_options.find(name);
+ auto iter = m_options->find(name);
- if (iter == m_options.end())
+ if (iter == m_options->end())
{
- throw option_not_exists_exception(name);
+ if (m_allow_unrecognised)
+ {
+ // keep unrecognised options in argument list, skip to next
argument
+ argv[nextKeep] = argv[current];
+ ++nextKeep;
+ ++current;
+ continue;
+ }
+ else
+ {
+ //error
+ throw option_not_exists_exception(name);
+ }
}
auto opt = iter->second;
@@ -1750,14 +1861,14 @@
++current;
}
- for (auto& opt : m_options)
+ for (auto& opt : *m_options)
{
auto& detail = opt.second;
auto& value = detail->value();
auto& store = m_results[detail];
- if(!store.count() && value.has_default()){
+ if(value.has_default() && !store.count() && !store.has_default()){
parse_default(detail);
}
}
@@ -1828,7 +1939,7 @@
std::shared_ptr<OptionDetails> details
)
{
- auto in = m_options.emplace(option, details);
+ auto in = m_options->emplace(option, details);
if (!in.second)
{
@@ -1861,19 +1972,18 @@
for (const auto& o : group->second.options)
{
- if (o.is_container &&
- m_positional_set.find(o.l) != m_positional_set.end() &&
+ 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));
+ longest = (std::max)(longest, stringLength(s));
format.push_back(std::make_pair(s, String()));
}
- longest = std::min(longest, static_cast<size_t>(OPTION_LONGEST));
+ longest = (std::min)(longest, static_cast<size_t>(OPTION_LONGEST));
//widest allowed description
auto allowed = size_t{76} - longest - OPTION_DESC_GAP;
@@ -1881,8 +1991,7 @@
auto fiter = format.begin();
for (const auto& o : group->second.options)
{
- if (o.is_container &&
- m_positional_set.find(o.l) != m_positional_set.end() &&
+ if (m_positional_set.find(o.l) != m_positional_set.end() &&
!m_show_positional)
{
continue;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cxxopts-2.1.2/src/example.cpp
new/cxxopts-2.2.1/src/example.cpp
--- old/cxxopts-2.1.2/src/example.cpp 2019-01-13 22:12:07.000000000 +0100
+++ new/cxxopts-2.2.1/src/example.cpp 2020-08-04 00:59:54.000000000 +0200
@@ -26,7 +26,8 @@
#include "cxxopts.hpp"
-int main(int argc, char* argv[])
+cxxopts::ParseResult
+parse(int argc, char* argv[])
{
try
{
@@ -37,7 +38,9 @@
bool apple = false;
- options.add_options()
+ options
+ .allow_unrecognised_options()
+ .add_options()
("a,apple", "an apple", cxxopts::value<bool>(apple))
("b,bob", "Bob")
("t,true", "True", cxxopts::value<bool>()->default_value("true"))
@@ -53,6 +56,7 @@
("help", "Print help")
("int", "An integer", cxxopts::value<int>(), "N")
("float", "A floating point number", cxxopts::value<float>())
+ ("vector", "A list of doubles", cxxopts::value<std::vector<double>>())
("option_that_is_too_long_for_the_help", "A very long option")
#ifdef CXXOPTS_USE_UNICODE
("unicode", u8"A help option with non-ascii: ??. Here the size of the"
@@ -127,13 +131,32 @@
std::cout << "float = " << result["float"].as<float>() << std::endl;
}
+ if (result.count("vector"))
+ {
+ std::cout << "vector = ";
+ const auto values = result["vector"].as<std::vector<double>>();
+ for (const auto& v : values) {
+ std::cout << v << ", ";
+ }
+ std::cout << std::endl;
+ }
+
std::cout << "Arguments remain = " << argc << std::endl;
+ return result;
+
} catch (const cxxopts::OptionException& e)
{
std::cout << "error parsing options: " << e.what() << std::endl;
exit(1);
}
+}
+
+int main(int argc, char* argv[])
+{
+ auto result = parse(argc, argv);
+ auto arguments = result.arguments();
+ std::cout << "Saw " << arguments.size() << " arguments" << std::endl;
return 0;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/cxxopts-2.1.2/test/options.cpp
new/cxxopts-2.2.1/test/options.cpp
--- old/cxxopts-2.1.2/test/options.cpp 2019-01-13 22:12:07.000000000 +0100
+++ new/cxxopts-2.2.1/test/options.cpp 2020-08-04 00:59:54.000000000 +0200
@@ -53,6 +53,7 @@
("a,av", "a short option with a value", cxxopts::value<std::string>())
("6,six", "a short number option")
("p, space", "an option with space between short and long")
+ ("nothing", "won't exist", cxxopts::value<std::string>())
;
Argv argv({
@@ -92,6 +93,8 @@
CHECK(arguments[1].key() == "short");
CHECK(arguments[2].key() == "value");
CHECK(arguments[3].key() == "av");
+
+ CHECK_THROWS_AS(result["nothing"].as<std::string>(), std::domain_error&);
}
TEST_CASE("Short options", "[options]")
@@ -111,8 +114,8 @@
CHECK(result.count("a") == 1);
CHECK(result["a"].as<std::string>() == "value");
- REQUIRE_THROWS_AS(options.add_options()("", "nothing option"),
- cxxopts::invalid_option_format_error);
+ REQUIRE_THROWS_AS(options.add_options()("", "nothing option"),
+ cxxopts::invalid_option_format_error&);
}
TEST_CASE("No positional", "[positional]")
@@ -145,7 +148,9 @@
auto argc = av.argc();
auto argv = av.argv();
- options.parse_positional({"positional"});
+ std::vector<std::string> pos_names = {"positional"};
+
+ options.parse_positional(pos_names.begin(), pos_names.end());
auto result = options.parse(argc, argv);
@@ -211,6 +216,22 @@
CHECK(argv[1] == std::string("a"));
}
+TEST_CASE("Positional not valid", "[positional]") {
+ cxxopts::Options options("positional_invalid", "invalid positional
argument");
+ options.add_options()
+ ("long", "a long option", cxxopts::value<std::string>())
+ ;
+
+ options.parse_positional("something");
+
+ Argv av({"foobar", "bar", "baz"});
+
+ char** argv = av.argv();
+ auto argc = av.argc();
+
+ CHECK_THROWS_AS(options.parse(argc, argv),
cxxopts::option_not_exists_exception&);
+}
+
TEST_CASE("Empty with implicit value", "[implicit]")
{
cxxopts::Options options("empty_implicit", "doesn't handle empty");
@@ -229,12 +250,75 @@
REQUIRE(result["implicit"].as<std::string>() == "");
}
+TEST_CASE("Boolean without implicit value", "[implicit]")
+{
+ cxxopts::Options options("no_implicit", "bool without an implicit value");
+ options.add_options()
+ ("bool", "Boolean without implicit", cxxopts::value<bool>()
+ ->no_implicit_value());
+
+ SECTION("When no value provided") {
+ Argv av({"no_implicit", "--bool"});
+
+ char** argv = av.argv();
+ auto argc = av.argc();
+
+ CHECK_THROWS_AS(options.parse(argc, argv),
cxxopts::missing_argument_exception&);
+ }
+
+ SECTION("With equal-separated true") {
+ Argv av({"no_implicit", "--bool=true"});
+
+ char** argv = av.argv();
+ auto argc = av.argc();
+
+ auto result = options.parse(argc, argv);
+ CHECK(result.count("bool") == 1);
+ CHECK(result["bool"].as<bool>() == true);
+ }
+
+ SECTION("With equal-separated false") {
+ Argv av({"no_implicit", "--bool=false"});
+
+ char** argv = av.argv();
+ auto argc = av.argc();
+
+ auto result = options.parse(argc, argv);
+ CHECK(result.count("bool") == 1);
+ CHECK(result["bool"].as<bool>() == false);
+ }
+
+ SECTION("With space-separated true") {
+ Argv av({"no_implicit", "--bool", "true"});
+
+ char** argv = av.argv();
+ auto argc = av.argc();
+
+ auto result = options.parse(argc, argv);
+ CHECK(result.count("bool") == 1);
+ CHECK(result["bool"].as<bool>() == true);
+ }
+
+ SECTION("With space-separated false") {
+ Argv av({"no_implicit", "--bool", "false"});
+
+ char** argv = av.argv();
+ auto argc = av.argc();
+
+ auto result = options.parse(argc, argv);
+ CHECK(result.count("bool") == 1);
+ CHECK(result["bool"].as<bool>() == false);
+ }
+}
+
TEST_CASE("Default values", "[default]")
{
cxxopts::Options options("defaults", "has defaults");
options.add_options()
- ("default", "Has implicit", cxxopts::value<int>()
- ->default_value("42"));
+ ("default", "Has implicit", cxxopts::value<int>()->default_value("42"))
+ ("v,vector", "Default vector", cxxopts::value<std::vector<int>>()
+ ->default_value("1,4"))
+ ;
SECTION("Sets defaults") {
Argv av({"implicit"});
@@ -245,6 +329,11 @@
auto result = options.parse(argc, argv);
CHECK(result.count("default") == 0);
CHECK(result["default"].as<int>() == 42);
+
+ auto& v = result["vector"].as<std::vector<int>>();
+ REQUIRE(v.size() == 2);
+ CHECK(v[0] == 1);
+ CHECK(v[1] == 4);
}
SECTION("When values provided") {
@@ -304,6 +393,30 @@
CHECK(positional[6] == 0x0);
}
+TEST_CASE("Leading zero integers", "[options]")
+{
+ cxxopts::Options options("parses_integers", "parses integers correctly");
+ options.add_options()
+ ("positional", "Integers", cxxopts::value<std::vector<int>>());
+
+ Argv av({"ints", "--", "05", "06", "0x0ab", "0x0001"});
+
+ char** argv = av.argv();
+ auto argc = av.argc();
+
+ options.parse_positional("positional");
+ auto result = options.parse(argc, argv);
+
+ REQUIRE(result.count("positional") == 4);
+
+ auto& positional = result["positional"].as<std::vector<int>>();
+ REQUIRE(positional.size() == 4);
+ CHECK(positional[0] == 5);
+ CHECK(positional[1] == 6);
+ CHECK(positional[2] == 0xab);
+ CHECK(positional[3] == 0x1);
+}
+
TEST_CASE("Unsigned integers", "[options]")
{
cxxopts::Options options("parses_unsigned", "detects unsigned errors");
@@ -316,7 +429,7 @@
auto argc = av.argc();
options.parse_positional("positional");
- CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type);
+ CHECK_THROWS_AS(options.parse(argc, argv),
cxxopts::argument_incorrect_type&);
}
TEST_CASE("Integer bounds", "[integer]")
@@ -353,16 +466,18 @@
int8_t si;
uint8_t ui;
- CHECK_THROWS_AS((integer_parser("128", si)),
cxxopts::argument_incorrect_type);
- CHECK_THROWS_AS((integer_parser("-129", si)),
cxxopts::argument_incorrect_type);
- CHECK_THROWS_AS((integer_parser("256", ui)),
cxxopts::argument_incorrect_type);
- CHECK_THROWS_AS((integer_parser("-0x81", si)),
cxxopts::argument_incorrect_type);
- CHECK_THROWS_AS((integer_parser("0x80", si)),
cxxopts::argument_incorrect_type);
- CHECK_THROWS_AS((integer_parser("0x100", ui)),
cxxopts::argument_incorrect_type);
+ CHECK_THROWS_AS((integer_parser("128", si)),
cxxopts::argument_incorrect_type&);
+ CHECK_THROWS_AS((integer_parser("-129", si)),
cxxopts::argument_incorrect_type&);
+ CHECK_THROWS_AS((integer_parser("256", ui)),
cxxopts::argument_incorrect_type&);
+ CHECK_THROWS_AS((integer_parser("-0x81", si)),
cxxopts::argument_incorrect_type&);
+ CHECK_THROWS_AS((integer_parser("0x80", si)),
cxxopts::argument_incorrect_type&);
+ CHECK_THROWS_AS((integer_parser("0x100", ui)),
cxxopts::argument_incorrect_type&);
}
TEST_CASE("Integer overflow", "[options]")
{
+ using namespace cxxopts::values;
+
cxxopts::Options options("reject_overflow", "rejects overflowing integers");
options.add_options()
("positional", "Integers", cxxopts::value<std::vector<int8_t>>());
@@ -373,7 +488,11 @@
auto argc = av.argc();
options.parse_positional("positional");
- CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type);
+ CHECK_THROWS_AS(options.parse(argc, argv),
cxxopts::argument_incorrect_type&);
+
+ int integer = 0;
+ CHECK_THROWS_AS((integer_parser("23423423423", integer)),
cxxopts::argument_incorrect_type&);
+ CHECK_THROWS_AS((integer_parser("234234234234", integer)),
cxxopts::argument_incorrect_type&);
}
TEST_CASE("Floats", "[options]")
@@ -414,7 +533,7 @@
auto argc = av.argc();
options.parse_positional("positional");
- CHECK_THROWS_AS(options.parse(argc, argv),
cxxopts::argument_incorrect_type);
+ CHECK_THROWS_AS(options.parse(argc, argv),
cxxopts::argument_incorrect_type&);
}
TEST_CASE("Booleans", "[boolean]") {
@@ -423,6 +542,8 @@
("bool", "A Boolean", cxxopts::value<bool>())
("debug", "Debugging", cxxopts::value<bool>())
("timing", "Timing", cxxopts::value<bool>())
+ ("verbose", "Verbose", cxxopts::value<bool>())
+ ("dry-run", "Dry Run", cxxopts::value<bool>())
("noExplicitDefault", "No Explicit Default", cxxopts::value<bool>())
("defaultTrue", "Timing", cxxopts::value<bool>()->default_value("true"))
("defaultFalse", "Timing", cxxopts::value<bool>()->default_value("false"))
@@ -431,7 +552,7 @@
options.parse_positional("others");
- Argv av({"booleans", "--bool=false", "--debug=true", "--timing", "extra"});
+ Argv av({"booleans", "--bool=false", "--debug=true", "--timing",
"--verbose=1", "--dry-run=0", "extra"});
char** argv = av.argv();
auto argc = av.argc();
@@ -441,6 +562,8 @@
REQUIRE(result.count("bool") == 1);
REQUIRE(result.count("debug") == 1);
REQUIRE(result.count("timing") == 1);
+ REQUIRE(result.count("verbose") == 1);
+ REQUIRE(result.count("dry-run") == 1);
REQUIRE(result.count("noExplicitDefault") == 0);
REQUIRE(result.count("defaultTrue") == 0);
REQUIRE(result.count("defaultFalse") == 0);
@@ -448,6 +571,8 @@
CHECK(result["bool"].as<bool>() == false);
CHECK(result["debug"].as<bool>() == true);
CHECK(result["timing"].as<bool>() == true);
+ CHECK(result["verbose"].as<bool>() == true);
+ CHECK(result["dry-run"].as<bool>() == false);
CHECK(result["noExplicitDefault"].as<bool>() == false);
CHECK(result["defaultTrue"].as<bool>() == true);
CHECK(result["defaultFalse"].as<bool>() == false);
@@ -455,6 +580,26 @@
REQUIRE(result.count("others") == 1);
}
+TEST_CASE("std::vector", "[vector]") {
+ std::vector<double> vector;
+ cxxopts::Options options("vector", " - tests vector");
+ options.add_options()
+ ("vector", "an vector option",
cxxopts::value<std::vector<double>>(vector));
+
+ Argv av({"vector", "--vector", "1,-2.1,3,4.5"});
+
+ char** argv = av.argv();
+ auto argc = av.argc();
+
+ options.parse(argc, argv);
+
+ REQUIRE(vector.size() == 4);
+ CHECK(vector[0] == 1);
+ CHECK(vector[1] == -2.1);
+ CHECK(vector[2] == 3);
+ CHECK(vector[3] == 4.5);
+}
+
#ifdef CXXOPTS_HAS_OPTIONAL
TEST_CASE("std::optional", "[optional]") {
std::optional<std::string> optional;
@@ -473,3 +618,76 @@
CHECK(*optional == "foo");
}
#endif
+
+TEST_CASE("Unrecognised options", "[options]") {
+ cxxopts::Options options("unknown_options", " - test unknown options");
+
+ options.add_options()
+ ("long", "a long option")
+ ("s,short", "a short option");
+
+ Argv av({
+ "unknown_options",
+ "--unknown",
+ "--long",
+ "-su",
+ "--another_unknown",
+ });
+
+ char** argv = av.argv();
+ auto argc = av.argc();
+
+ SECTION("Default behaviour") {
+ CHECK_THROWS_AS(options.parse(argc, argv),
cxxopts::option_not_exists_exception&);
+ }
+
+ SECTION("After allowing unrecognised options") {
+ options.allow_unrecognised_options();
+ CHECK_NOTHROW(options.parse(argc, argv));
+ REQUIRE(argc == 3);
+ CHECK_THAT(argv[1], Catch::Equals("--unknown"));
+ }
+}
+
+TEST_CASE("Allow bad short syntax", "[options]") {
+ cxxopts::Options options("unknown_options", " - test unknown options");
+
+ options.add_options()
+ ("long", "a long option")
+ ("s,short", "a short option");
+
+ Argv av({
+ "unknown_options",
+ "-some_bad_short",
+ });
+
+ char** argv = av.argv();
+ auto argc = av.argc();
+
+ SECTION("Default behaviour") {
+ CHECK_THROWS_AS(options.parse(argc, argv),
cxxopts::option_syntax_exception&);
+ }
+
+ SECTION("After allowing unrecognised options") {
+ options.allow_unrecognised_options();
+ CHECK_NOTHROW(options.parse(argc, argv));
+ REQUIRE(argc == 2);
+ CHECK_THAT(argv[1], Catch::Equals("-some_bad_short"));
+ }
+}
+
+TEST_CASE("Invalid option syntax", "[options]") {
+ cxxopts::Options options("invalid_syntax", " - test invalid syntax");
+
+ Argv av({
+ "invalid_syntax",
+ "--a",
+ });
+
+ char** argv = av.argv();
+ auto argc = av.argc();
+
+ SECTION("Default behaviour") {
+ CHECK_THROWS_AS(options.parse(argc, argv),
cxxopts::option_syntax_exception&);
+ }
+}