Support 'const char**' arguments in Options::parse (#250)

`cxxopts` doesn't modify the contents of the argv strings. This changes
the parse function to take a reference to a `const char**`.
This commit is contained in:
Kjetil Andresen 2020-08-11 00:01:29 +02:00 committed by GitHub
parent 07f5cb24f1
commit 15e8a74e95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 40 deletions

View File

@ -12,6 +12,7 @@ options. The project adheres to semantic versioning.
* Fix duplicate default options when there is a short and long option. * Fix duplicate default options when there is a short and long option.
* Add `CXXOPTS_NO_EXCEPTIONS` to disable exceptions. * Add `CXXOPTS_NO_EXCEPTIONS` to disable exceptions.
* Fix char parsing for space and check for length. * Fix char parsing for space and check for length.
* Change argument type in `Options::parse` from `char**` to `const char**`.
## 2.2 ## 2.2

View File

@ -1211,7 +1211,7 @@ namespace cxxopts
>, >,
std::vector<std::string>, std::vector<std::string>,
bool allow_unrecognised, bool allow_unrecognised,
int&, char**&); int&, const char**&);
size_t size_t
count(const std::string& o) const count(const std::string& o) const
@ -1251,7 +1251,7 @@ namespace cxxopts
private: private:
void void
parse(int& argc, char**& argv); parse(int& argc, const char**& argv);
void void
add_to_option(const std::string& option, const std::string& arg); add_to_option(const std::string& option, const std::string& arg);
@ -1274,7 +1274,7 @@ namespace cxxopts
checked_parse_arg checked_parse_arg
( (
int argc, int argc,
char* argv[], const char* argv[],
int& current, int& current,
const std::shared_ptr<OptionDetails>& value, const std::shared_ptr<OptionDetails>& value,
const std::string& name const std::string& name
@ -1361,7 +1361,7 @@ namespace cxxopts
} }
ParseResult ParseResult
parse(int& argc, char**& argv); parse(int& argc, const char**& argv);
OptionAdder OptionAdder
add_options(std::string group = ""); add_options(std::string group = "");
@ -1620,7 +1620,7 @@ ParseResult::ParseResult
> options, > options,
std::vector<std::string> positional, std::vector<std::string> positional,
bool allow_unrecognised, bool allow_unrecognised,
int& argc, char**& argv int& argc, const char**& argv
) )
: m_options(std::move(options)) : m_options(std::move(options))
, m_positional(std::move(positional)) , m_positional(std::move(positional))
@ -1734,7 +1734,7 @@ void
ParseResult::checked_parse_arg ParseResult::checked_parse_arg
( (
int argc, int argc,
char* argv[], const char* argv[],
int& current, int& current,
const std::shared_ptr<OptionDetails>& value, const std::shared_ptr<OptionDetails>& value,
const std::string& name const std::string& name
@ -1835,7 +1835,7 @@ Options::parse_positional(std::initializer_list<std::string> options)
inline inline
ParseResult ParseResult
Options::parse(int& argc, char**& argv) Options::parse(int& argc, const char**& argv)
{ {
ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv); ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv);
return result; return result;
@ -1843,7 +1843,7 @@ Options::parse(int& argc, char**& argv)
inline inline
void void
ParseResult::parse(int& argc, char**& argv) ParseResult::parse(int& argc, const char**& argv)
{ {
int current = 1; int current = 1;

View File

@ -27,7 +27,7 @@ THE SOFTWARE.
#include "cxxopts.hpp" #include "cxxopts.hpp"
void void
parse(int argc, char* argv[]) parse(int argc, const char* argv[])
{ {
try try
{ {
@ -160,7 +160,7 @@ parse(int argc, char* argv[])
} }
} }
int main(int argc, char* argv[]) int main(int argc, const char* argv[])
{ {
parse(argc, argv); parse(argc, argv);

View File

@ -8,7 +8,7 @@ class Argv {
public: public:
Argv(std::initializer_list<const char*> args) Argv(std::initializer_list<const char*> args)
: m_argv(new char*[args.size()]) : m_argv(new const char*[args.size()])
, m_argc(static_cast<int>(args.size())) , m_argc(static_cast<int>(args.size()))
{ {
int i = 0; int i = 0;
@ -26,7 +26,7 @@ class Argv {
} }
} }
char** argv() const { const char** argv() const {
return m_argv.get(); return m_argv.get();
} }
@ -37,7 +37,7 @@ class Argv {
private: private:
std::vector<std::unique_ptr<char[]>> m_args; std::vector<std::unique_ptr<char[]>> m_args;
std::unique_ptr<char*[]> m_argv; std::unique_ptr<const char*[]> m_argv;
int m_argc; int m_argc;
}; };
@ -69,7 +69,7 @@ TEST_CASE("Basic options", "[options]")
"--space", "--space",
}); });
char** actual_argv = argv.argv(); auto** actual_argv = argv.argv();
auto argc = argv.argc(); auto argc = argv.argc();
auto result = options.parse(argc, actual_argv); auto result = options.parse(argc, actual_argv);
@ -125,7 +125,7 @@ TEST_CASE("No positional", "[positional]")
Argv av({"tester", "a", "b", "def"}); Argv av({"tester", "a", "b", "def"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
@ -177,7 +177,7 @@ TEST_CASE("Some positional explicit", "[positional]")
Argv av({"tester", "--output", "a", "b", "c", "d"}); Argv av({"tester", "--output", "a", "b", "c", "d"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
@ -203,7 +203,7 @@ TEST_CASE("No positional with extras", "[positional]")
Argv av({"extras", "--", "a", "b", "c", "d"}); Argv av({"extras", "--", "a", "b", "c", "d"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
auto old_argv = argv; auto old_argv = argv;
@ -226,7 +226,7 @@ TEST_CASE("Positional not valid", "[positional]") {
Argv av({"foobar", "bar", "baz"}); Argv av({"foobar", "bar", "baz"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_not_exists_exception&); CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_not_exists_exception&);
@ -241,7 +241,7 @@ TEST_CASE("Empty with implicit value", "[implicit]")
Argv av({"implicit", "--implicit="}); Argv av({"implicit", "--implicit="});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
@ -260,7 +260,7 @@ TEST_CASE("Boolean without implicit value", "[implicit]")
SECTION("When no value provided") { SECTION("When no value provided") {
Argv av({"no_implicit", "--bool"}); Argv av({"no_implicit", "--bool"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::missing_argument_exception&); CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::missing_argument_exception&);
@ -269,7 +269,7 @@ TEST_CASE("Boolean without implicit value", "[implicit]")
SECTION("With equal-separated true") { SECTION("With equal-separated true") {
Argv av({"no_implicit", "--bool=true"}); Argv av({"no_implicit", "--bool=true"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
@ -280,7 +280,7 @@ TEST_CASE("Boolean without implicit value", "[implicit]")
SECTION("With equal-separated false") { SECTION("With equal-separated false") {
Argv av({"no_implicit", "--bool=false"}); Argv av({"no_implicit", "--bool=false"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
@ -291,7 +291,7 @@ TEST_CASE("Boolean without implicit value", "[implicit]")
SECTION("With space-separated true") { SECTION("With space-separated true") {
Argv av({"no_implicit", "--bool", "true"}); Argv av({"no_implicit", "--bool", "true"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
@ -302,7 +302,7 @@ TEST_CASE("Boolean without implicit value", "[implicit]")
SECTION("With space-separated false") { SECTION("With space-separated false") {
Argv av({"no_implicit", "--bool", "false"}); Argv av({"no_implicit", "--bool", "false"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
@ -323,7 +323,7 @@ TEST_CASE("Default values", "[default]")
SECTION("Sets defaults") { SECTION("Sets defaults") {
Argv av({"implicit"}); Argv av({"implicit"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
@ -339,7 +339,7 @@ TEST_CASE("Default values", "[default]")
SECTION("When values provided") { SECTION("When values provided") {
Argv av({"implicit", "--default", "5"}); Argv av({"implicit", "--default", "5"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
@ -374,7 +374,7 @@ TEST_CASE("Integers", "[options]")
Argv av({"ints", "--", "5", "6", "-6", "0", "0xab", "0xAf", "0x0"}); Argv av({"ints", "--", "5", "6", "-6", "0", "0xab", "0xAf", "0x0"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
options.parse_positional("positional"); options.parse_positional("positional");
@ -401,7 +401,7 @@ TEST_CASE("Leading zero integers", "[options]")
Argv av({"ints", "--", "05", "06", "0x0ab", "0x0001"}); Argv av({"ints", "--", "05", "06", "0x0ab", "0x0001"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
options.parse_positional("positional"); options.parse_positional("positional");
@ -425,7 +425,7 @@ TEST_CASE("Unsigned integers", "[options]")
Argv av({"ints", "--", "-2"}); Argv av({"ints", "--", "-2"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
options.parse_positional("positional"); options.parse_positional("positional");
@ -504,7 +504,7 @@ TEST_CASE("Floats", "[options]")
Argv av({"floats", "--double", "0.5", "--", "4", "-4", "1.5e6", "-1.5e6"}); Argv av({"floats", "--double", "0.5", "--", "4", "-4", "1.5e6", "-1.5e6"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
options.parse_positional("positional"); options.parse_positional("positional");
@ -529,7 +529,7 @@ TEST_CASE("Invalid integers", "[integer]") {
Argv av({"ints", "--", "Ae"}); Argv av({"ints", "--", "Ae"});
char **argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
options.parse_positional("positional"); options.parse_positional("positional");
@ -554,7 +554,7 @@ TEST_CASE("Booleans", "[boolean]") {
Argv av({"booleans", "--bool=false", "--debug=true", "--timing", "--verbose=1", "--dry-run=0", "extra"}); Argv av({"booleans", "--bool=false", "--debug=true", "--timing", "--verbose=1", "--dry-run=0", "extra"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
@ -588,7 +588,7 @@ TEST_CASE("std::vector", "[vector]") {
Argv av({"vector", "--vector", "1,-2.1,3,4.5"}); Argv av({"vector", "--vector", "1,-2.1,3,4.5"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
options.parse(argc, argv); options.parse(argc, argv);
@ -609,7 +609,7 @@ TEST_CASE("std::optional", "[optional]") {
Argv av({"optional", "--optional", "foo"}); Argv av({"optional", "--optional", "foo"});
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
options.parse(argc, argv); options.parse(argc, argv);
@ -634,7 +634,7 @@ TEST_CASE("Unrecognised options", "[options]") {
"--another_unknown", "--another_unknown",
}); });
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
SECTION("Default behaviour") { SECTION("Default behaviour") {
@ -661,7 +661,7 @@ TEST_CASE("Allow bad short syntax", "[options]") {
"-some_bad_short", "-some_bad_short",
}); });
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
SECTION("Default behaviour") { SECTION("Default behaviour") {
@ -684,7 +684,7 @@ TEST_CASE("Invalid option syntax", "[options]") {
"--a", "--a",
}); });
char** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
SECTION("Default behaviour") { SECTION("Default behaviour") {
@ -704,7 +704,7 @@ TEST_CASE("Options empty", "[options]") {
"--unknown" "--unknown"
}); });
auto argc = argv_.argc(); auto argc = argv_.argc();
char** argv = argv_.argv(); auto** argv = argv_.argv();
CHECK(options.groups().empty()); CHECK(options.groups().empty());
CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_not_exists_exception&); CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::option_not_exists_exception&);
@ -733,7 +733,7 @@ TEST_CASE("Initializer list with group", "[options]") {
"8000", "8000",
"-t", "-t",
}); });
char** actual_argv = argv.argv(); auto** actual_argv = argv.argv();
auto argc = argv.argc(); auto argc = argv.argc();
auto result = options.parse(argc, actual_argv); auto result = options.parse(argc, actual_argv);
@ -763,7 +763,7 @@ TEST_CASE("Option add with add_option(string, Option)", "[options]") {
"4" "4"
}); });
auto argc = argv_.argc(); auto argc = argv_.argc();
char** argv = argv_.argv(); auto** argv = argv_.argv();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
CHECK(result.arguments().size()==2); CHECK(result.arguments().size()==2);