我修改了cxxopts.hpp源文件的parse方法,使得长短选项都以-来匹配,之前--匹配的长选项不再适用,-开头的选项,不是长选项就是短选项,所以-su会被认定为长选项,并且修改了text文件夹options.cpp中的某些测试用例,基于’-‘能匹配长短选项,所以就不存在测试用例中的Allow_bad_short_syntax这样的一个情况,并且长短选项都可以用=赋值,比如"-a=20"是被允许的,之前的源文件这样的赋值操作是不匹配的

This commit is contained in:
zrshonor 2021-07-07 15:05:02 +08:00 committed by ZrsWorkSpace
parent 174510285a
commit 95a43acccf
3 changed files with 1958 additions and 2123 deletions

View File

@ -1,17 +1,14 @@
/* /*
Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -19,7 +16,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
#ifndef CXXOPTS_HPP_INCLUDED #ifndef CXXOPTS_HPP_INCLUDED
@ -665,7 +661,7 @@ namespace cxxopts
void stringstream_parser(const std::string& text, T& value) void stringstream_parser(const std::string& text, T& value)
{ {
std::stringstream in(text); std::stringstream in(text);
in >> value; in >> value; //!!!!niubi!
if (!in) { if (!in) {
throw_or_mimic<argument_incorrect_type>(text); throw_or_mimic<argument_incorrect_type>(text);
} }
@ -778,7 +774,6 @@ namespace cxxopts
value.emplace_back(std::move(v)); value.emplace_back(std::move(v));
} }
} }
#ifdef CXXOPTS_HAS_OPTIONAL #ifdef CXXOPTS_HAS_OPTIONAL
template <typename T> template <typename T>
void void
@ -1136,7 +1131,7 @@ namespace cxxopts
#if defined(__GNUC__) #if defined(__GNUC__)
#if __GNUC__ <= 10 && __GNUC_MINOR__ <= 1 #if __GNUC__ <= 10 && __GNUC_MINOR__ <= 1
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Werror=null-dereference" #pragma GCC diagnostic ignored "-Werror=null-dereference"
#endif #endif
#endif #endif
@ -1580,7 +1575,7 @@ namespace cxxopts
constexpr size_t OPTION_DESC_GAP = 2; constexpr size_t OPTION_DESC_GAP = 2;
std::basic_regex<char> option_matcher std::basic_regex<char> option_matcher
("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)"); ("-([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]{1})(=(.*))?");
std::basic_regex<char> option_specifier std::basic_regex<char> option_specifier
("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?"); ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
@ -1762,38 +1757,38 @@ namespace cxxopts
} }
} // namespace } // namespace
inline inline
void void
Options::add_options Options::add_options
( (
const std::string &group, const std::string &group,
std::initializer_list<Option> options std::initializer_list<Option> options
) )
{ {
OptionAdder option_adder(*this, group); OptionAdder option_adder(*this, group);
for (const auto &option: options) for (const auto &option: options)
{ {
option_adder(option.opts_, option.desc_, option.value_, option.arg_help_); option_adder(option.opts_, option.desc_, option.value_, option.arg_help_);
} }
} }
inline inline
OptionAdder OptionAdder
Options::add_options(std::string group) Options::add_options(std::string group)
{ {
return OptionAdder(*this, std::move(group)); return OptionAdder(*this, std::move(group));
} }
inline inline
OptionAdder& OptionAdder&
OptionAdder::operator() OptionAdder::operator()
( (
const std::string& opts, const std::string& opts,
const std::string& desc, const std::string& desc,
const std::shared_ptr<const Value>& value, const std::shared_ptr<const Value>& value,
std::string arg_help std::string arg_help
) )
{ {
std::match_results<const char*> result; std::match_results<const char*> result;
std::regex_match(opts.c_str(), result, option_specifier); std::regex_match(opts.c_str(), result, option_specifier);
@ -1837,44 +1832,44 @@ OptionAdder::operator()
); );
return *this; return *this;
} }
inline inline
void void
OptionParser::parse_default(const std::shared_ptr<OptionDetails>& details) OptionParser::parse_default(const std::shared_ptr<OptionDetails>& details)
{ {
// TODO: remove the duplicate code here // ggTODO: remove the duplicate code here
auto& store = m_parsed[details->hash()]; auto& store = m_parsed[details->hash()];
store.parse_default(details); store.parse_default(details);
} }
inline inline
void void
OptionParser::parse_option OptionParser::parse_option
( (
const std::shared_ptr<OptionDetails>& value, const std::shared_ptr<OptionDetails>& value,
const std::string& /*name*/, const std::string& /*name*/,
const std::string& arg const std::string& arg
) )
{ {
auto hash = value->hash(); auto hash = value->hash();
auto& result = m_parsed[hash]; auto& result = m_parsed[hash];
result.parse(value, arg); result.parse(value, arg);
m_sequential.emplace_back(value->long_name(), arg); m_sequential.emplace_back(value->long_name(), arg);
} }
inline inline
void void
OptionParser::checked_parse_arg OptionParser::checked_parse_arg
( (
int argc, int argc,
const char* const* argv, const char* const* 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
) )
{ {
if (current + 1 >= argc) if (current + 1 >= argc)
{ {
if (value->value().has_implicit()) if (value->value().has_implicit())
@ -1898,19 +1893,19 @@ OptionParser::checked_parse_arg
++current; ++current;
} }
} }
} }
inline inline
void void
OptionParser::add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg) OptionParser::add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg)
{ {
parse_option(iter->second, option, arg); parse_option(iter->second, option, arg);
} }
inline inline
bool bool
OptionParser::consume_positional(const std::string& a, PositionalListIterator& next) OptionParser::consume_positional(const std::string& a, PositionalListIterator& next)
{ {
while (next != m_positional.end()) while (next != m_positional.end())
{ {
auto iter = m_options.find(*next); auto iter = m_options.find(*next);
@ -1935,43 +1930,43 @@ OptionParser::consume_positional(const std::string& a, PositionalListIterator& n
} }
return false; return false;
} }
inline inline
void void
Options::parse_positional(std::string option) Options::parse_positional(std::string option)
{ {
parse_positional(std::vector<std::string>{std::move(option)}); parse_positional(std::vector<std::string>{std::move(option)});
} }
inline inline
void void
Options::parse_positional(std::vector<std::string> options) Options::parse_positional(std::vector<std::string> options)
{ {
m_positional = std::move(options); m_positional = std::move(options);
m_positional_set.insert(m_positional.begin(), m_positional.end()); m_positional_set.insert(m_positional.begin(), m_positional.end());
} }
inline inline
void void
Options::parse_positional(std::initializer_list<std::string> options) Options::parse_positional(std::initializer_list<std::string> options)
{ {
parse_positional(std::vector<std::string>(options)); parse_positional(std::vector<std::string>(options));
} }
inline inline
ParseResult ParseResult
Options::parse(int argc, const char* const* argv) Options::parse(int argc, const char* const* argv)
{ {
OptionParser parser(*m_options, m_positional, m_allow_unrecognised); OptionParser parser(*m_options, m_positional, m_allow_unrecognised);
return parser.parse(argc, argv); return parser.parse(argc, argv);
} }
inline ParseResult inline ParseResult
OptionParser::parse(int argc, const char* const* argv) OptionParser::parse(int argc, const char* const* argv)
{ {
int current = 1; int current = 1;
bool consume_remaining = false; bool consume_remaining = false;
auto next_positional = m_positional.begin(); auto next_positional = m_positional.begin();
@ -1980,7 +1975,7 @@ OptionParser::parse(int argc, const char* const* argv)
while (current != argc) while (current != argc)
{ {
if (strcmp(argv[current], "--") == 0) if (strcmp(argv[current], "-") == 0)
{ {
consume_remaining = true; consume_remaining = true;
++current; ++current;
@ -2018,38 +2013,21 @@ OptionParser::parse(int argc, const char* const* argv)
if (result[4].length() != 0) if (result[4].length() != 0)
{ {
const std::string& s = result[4]; const std::string& s = result[4];
auto iter = m_options.find(s);
for (std::size_t i = 0; i != s.size(); ++i) if(iter==m_options.end()){
{ if(!m_allow_unrecognised){
std::string name(1, s[i]); throw_or_mimic<option_not_exists_exception>(s);
auto iter = m_options.find(name); }
++current;
if (iter == m_options.end())
{
if (m_allow_unrecognised)
{
continue; continue;
} }
//error
throw_or_mimic<option_not_exists_exception>(name);
}
auto value = iter->second; auto value = iter->second;
if (i + 1 == s.size()) if(result[5].length()!=0){
{ parse_option(value,s,result[6]);
//it must be the last argument std::cout<<"The value is"<<result[6].str()<<std::endl;
checked_parse_arg(argc, argv, current, value, name); }else{
} checked_parse_arg(argc,argv,current,value,s);
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) else if (result[1].length() != 0)
@ -2077,7 +2055,6 @@ OptionParser::parse(int argc, const char* const* argv)
if (result[2].length() != 0) if (result[2].length() != 0)
{ {
//parse the option given //parse the option given
parse_option(opt, name, result[3]); parse_option(opt, name, result[3]);
} }
else else
@ -2088,7 +2065,6 @@ OptionParser::parse(int argc, const char* const* argv)
} }
} }
++current; ++current;
} }
@ -2125,12 +2101,12 @@ OptionParser::parse(int argc, const char* const* argv)
ParseResult parsed(std::move(m_keys), std::move(m_parsed), std::move(m_sequential), std::move(unmatched)); ParseResult parsed(std::move(m_keys), std::move(m_parsed), std::move(m_sequential), std::move(unmatched));
return parsed; return parsed;
} }
inline inline
void void
OptionParser::finalise_aliases() OptionParser::finalise_aliases()
{ {
for (auto& option: m_options) for (auto& option: m_options)
{ {
auto& detail = *option.second; auto& detail = *option.second;
@ -2140,31 +2116,31 @@ OptionParser::finalise_aliases()
m_parsed.emplace(hash, OptionValue()); m_parsed.emplace(hash, OptionValue());
} }
} }
inline inline
void void
Options::add_option Options::add_option
( (
const std::string& group, const std::string& group,
const Option& option const Option& option
) )
{ {
add_options(group, {option}); add_options(group, {option});
} }
inline inline
void void
Options::add_option Options::add_option
( (
const std::string& group, const std::string& group,
const std::string& s, const std::string& s,
const std::string& l, const std::string& l,
std::string desc, std::string desc,
const std::shared_ptr<const Value>& value, const std::shared_ptr<const Value>& value,
std::string arg_help std::string arg_help
) )
{ {
auto stringDesc = toLocalString(std::move(desc)); auto stringDesc = toLocalString(std::move(desc));
auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value); auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);
@ -2192,28 +2168,28 @@ Options::add_option
std::move(arg_help), std::move(arg_help),
value->is_container(), value->is_container(),
value->is_boolean()}); value->is_boolean()});
} }
inline inline
void void
Options::add_one_option Options::add_one_option
( (
const std::string& option, const std::string& option,
const std::shared_ptr<OptionDetails>& details const std::shared_ptr<OptionDetails>& details
) )
{ {
auto in = m_options->emplace(option, details); auto in = m_options->emplace(option, details);
if (!in.second) if (!in.second)
{ {
throw_or_mimic<option_exists_error>(option); throw_or_mimic<option_exists_error>(option);
} }
} }
inline inline
String String
Options::help_one_group(const std::string& g) const Options::help_one_group(const std::string& g) const
{ {
using OptionHelp = std::vector<std::pair<String, String>>; using OptionHelp = std::vector<std::pair<String, String>>;
auto group = m_help.find(g); auto group = m_help.find(g);
@ -2284,16 +2260,16 @@ Options::help_one_group(const std::string& g) const
} }
return result; return result;
} }
inline inline
void void
Options::generate_group_help Options::generate_group_help
( (
String& result, String& result,
const std::vector<std::string>& print_groups const std::vector<std::string>& print_groups
) const ) const
{ {
for (size_t i = 0; i != print_groups.size(); ++i) for (size_t i = 0; i != print_groups.size(); ++i)
{ {
const String& group_help_text = help_one_group(print_groups[i]); const String& group_help_text = help_one_group(print_groups[i]);
@ -2307,12 +2283,12 @@ Options::generate_group_help
result += '\n'; result += '\n';
} }
} }
} }
inline inline
void void
Options::generate_all_groups_help(String& result) const Options::generate_all_groups_help(String& result) const
{ {
std::vector<std::string> all_groups; std::vector<std::string> all_groups;
std::transform( std::transform(
@ -2326,12 +2302,12 @@ Options::generate_all_groups_help(String& result) const
); );
generate_group_help(result, all_groups); generate_group_help(result, all_groups);
} }
inline inline
std::string std::string
Options::help(const std::vector<std::string>& help_groups) const Options::help(const std::vector<std::string>& help_groups) const
{ {
String result = m_help_string + "\nUsage:\n " + String result = m_help_string + "\nUsage:\n " +
toLocalString(m_program) + " " + toLocalString(m_custom_help); toLocalString(m_program) + " " + toLocalString(m_custom_help);
@ -2351,12 +2327,12 @@ Options::help(const std::vector<std::string>& help_groups) const
} }
return toUTF8String(result); return toUTF8String(result);
} }
inline inline
std::vector<std::string> std::vector<std::string>
Options::groups() const Options::groups() const
{ {
std::vector<std::string> g; std::vector<std::string> g;
std::transform( std::transform(
@ -2370,15 +2346,16 @@ Options::groups() const
); );
return g; return g;
} }
inline inline
const HelpGroupDetails& const HelpGroupDetails&
Options::group_help(const std::string& group) const Options::group_help(const std::string& group) const
{ {
return m_help.at(group); return m_help.at(group);
} }
} // namespace cxxopts } // namespace cxxopts
#endif //CXXOPTS_HPP_INCLUDED #endif //CXXOPTS_HPP_INCLUDED

View File

@ -1,171 +1,57 @@
/*
Copyright (c) 2014 Jarryd Beck #include<cxxopts.hpp>
#include<iostream>
#include<vector>
using namespace std;
Permission is hereby granted, free of charge, to any person obtaining a copy void parse(int argc,const char* argv[]){
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 try{
all copies or substantial portions of the Software. cxxopts::Options options(argv[0],"My test example");
options.allow_unrecognised_options();
options.show_positional_help();
options.set_width(70).set_tab_expansion().add_options("MyOption")
("f,float","a float variable",cxxopts::value<float>()->implicit_value("10"),"file")
("i,int","a integer variable",cxxopts::value<int>())
("l,float_list","a float list",cxxopts::value<vector<float>>())
("help","print help");
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR auto result = options.parse(argc,argv);
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.
*/ if(result.count("help")){
cout<<options.help({"MyOption"})<<endl;
#include <iostream>
#include "cxxopts.hpp"
void
parse(int argc, const char* argv[])
{
try
{
cxxopts::Options options(argv[0], " - example command line options");
options
.positional_help("[optional args]")
.show_positional_help();
bool apple = false;
options
.set_width(70)
.set_tab_expansion()
.allow_unrecognised_options()
.add_options()
("a,apple", "an apple", cxxopts::value<bool>(apple))
("b,bob", "Bob")
("char", "A character", cxxopts::value<char>())
("t,true", "True", cxxopts::value<bool>()->default_value("true"))
("f, file", "File", cxxopts::value<std::vector<std::string>>(), "FILE")
("i,input", "Input", cxxopts::value<std::string>())
("o,output", "Output file", cxxopts::value<std::string>()
->default_value("a.out")->implicit_value("b.def"), "BIN")
("x", "A short-only option", cxxopts::value<std::string>())
("positional",
"Positional arguments: these are the arguments that are entered "
"without an option", cxxopts::value<std::vector<std::string>>())
("long-description",
"thisisareallylongwordthattakesupthewholelineandcannotbebrokenataspace")
("help", "Print help")
("tab-expansion", "Tab\texpansion")
("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"
" string should be correct")
#endif
;
options.add_options("Group")
("c,compile", "compile")
("d,drop", "drop", cxxopts::value<std::vector<std::string>>());
options.parse_positional({"input", "output", "positional"});
auto result = options.parse(argc, argv);
if (result.count("help"))
{
std::cout << options.help({"", "Group"}) << std::endl;
exit(0); exit(0);
} }
if(result.count("i")){
if (apple) cout<<"Saw the argument of int "<<result.count("i")<<" times"<<endl;
{ cout<<"The last value is "<<result["i"].as<int>()<<endl;
std::cout << "Saw option a " << result.count("a") << " times " <<
std::endl;
} }
if(result.count("f")){
if (result.count("b")) cout<<"Saw the argument of float "<<result.count("f")<<" times"<<endl;
{ cout<<"The last value is "<<result["f"].as<float>()<<endl;
std::cout << "Saw option b" << std::endl;
} }
if(result.count("l")){
if (result.count("char")) auto list = result["l"].as<vector<float>>();
{ for(auto data:list){
std::cout << "Saw a character " << result["char"].as<char>() << "" << std::endl; cout<<data<<" ";
} }
cout<<endl;
if (result.count("f"))
{
auto& ff = result["f"].as<std::vector<std::string>>();
std::cout << "Files" << std::endl;
for (const auto& f : ff)
{
std::cout << f << std::endl;
} }
auto unmatched = result.unmatched();
for(auto data:unmatched){
cout<<data<<" ";
} }
cout<<endl;
if (result.count("input")) }catch (cxxopts::OptionException &e){
{ e.what();
std::cout << "Input = " << result["input"].as<std::string>()
<< std::endl;
}
if (result.count("output"))
{
std::cout << "Output = " << result["output"].as<std::string>()
<< std::endl;
}
if (result.count("positional"))
{
std::cout << "Positional = {";
auto& v = result["positional"].as<std::vector<std::string>>();
for (const auto& s : v) {
std::cout << s << ", ";
}
std::cout << "}" << std::endl;
}
if (result.count("int"))
{
std::cout << "int = " << result["int"].as<int>() << std::endl;
}
if (result.count("float"))
{
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;
auto arguments = result.arguments();
std::cout << "Saw " << arguments.size() << " arguments" << std::endl;
}
catch (const cxxopts::OptionException& e)
{
std::cout << "error parsing options: " << e.what() << std::endl;
exit(1);
} }
} }
int main(int argc, const char* argv[]) int main(){
{ int argc = 11;
parse(argc, argv); const char* argv[] = {"My_Group","-int","10","-i=30","20","-f","30","-help","40","-l","30,20,30,40,50,60"};
parse(argc,argv);
return 0; return 0;
} }

View File

@ -58,15 +58,15 @@ TEST_CASE("Basic options", "[options]")
Argv argv({ Argv argv({
"tester", "tester",
"--long", "-long",
"-s", "-s",
"--value", "-value",
"value", "value",
"-a", "-a",
"b", "b",
"-6", "-6",
"-p", "-p",
"--space", "-space",
}); });
auto** actual_argv = argv.argv(); auto** actual_argv = argv.argv();
@ -175,7 +175,7 @@ TEST_CASE("Some positional explicit", "[positional]")
options.parse_positional({"input", "output", "positional"}); options.parse_positional({"input", "output", "positional"});
Argv av({"tester", "--output", "a", "b", "c", "d"}); Argv av({"tester", "-output", "a", "b", "c", "d"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -201,7 +201,7 @@ TEST_CASE("No positional with extras", "[positional]")
("dummy", "oh no", cxxopts::value<std::string>()) ("dummy", "oh no", cxxopts::value<std::string>())
; ;
Argv av({"extras", "--", "a", "b", "c", "d"}); Argv av({"extras", "-", "a", "b", "c", "d"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -238,7 +238,7 @@ TEST_CASE("Empty with implicit value", "[implicit]")
("implicit", "Has implicit", cxxopts::value<std::string>() ("implicit", "Has implicit", cxxopts::value<std::string>()
->implicit_value("foo")); ->implicit_value("foo"));
Argv av({"implicit", "--implicit="}); Argv av({"implicit", "-implicit="});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -257,7 +257,7 @@ TEST_CASE("Boolean without implicit value", "[implicit]")
->no_implicit_value()); ->no_implicit_value());
SECTION("When no value provided") { SECTION("When no value provided") {
Argv av({"no_implicit", "--bool"}); Argv av({"no_implicit", "-bool"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -266,7 +266,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"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -277,7 +277,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"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -288,7 +288,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"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -299,7 +299,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"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -336,7 +336,7 @@ TEST_CASE("Default values", "[default]")
} }
SECTION("When values provided") { SECTION("When values provided") {
Argv av({"implicit", "--default", "5"}); Argv av({"implicit", "-default", "5"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -355,7 +355,7 @@ TEST_CASE("Parse into a reference", "[reference]")
options.add_options() options.add_options()
("ref", "A reference", cxxopts::value(value)); ("ref", "A reference", cxxopts::value(value));
Argv av({"into_reference", "--ref", "42"}); Argv av({"into_reference", "-ref", "42"});
auto argv = av.argv(); auto argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -371,7 +371,7 @@ TEST_CASE("Integers", "[options]")
options.add_options() options.add_options()
("positional", "Integers", cxxopts::value<std::vector<int>>()); ("positional", "Integers", cxxopts::value<std::vector<int>>());
Argv av({"ints", "--", "5", "6", "-6", "0", "0xab", "0xAf", "0x0"}); Argv av({"ints", "-", "5", "6", "-6", "0", "0xab", "0xAf", "0x0"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -398,7 +398,7 @@ TEST_CASE("Leading zero integers", "[options]")
options.add_options() options.add_options()
("positional", "Integers", cxxopts::value<std::vector<int>>()); ("positional", "Integers", cxxopts::value<std::vector<int>>());
Argv av({"ints", "--", "05", "06", "0x0ab", "0x0001"}); Argv av({"ints", "-", "05", "06", "0x0ab", "0x0001"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -422,7 +422,7 @@ TEST_CASE("Unsigned integers", "[options]")
options.add_options() options.add_options()
("positional", "Integers", cxxopts::value<std::vector<unsigned int>>()); ("positional", "Integers", cxxopts::value<std::vector<unsigned int>>());
Argv av({"ints", "--", "-2"}); Argv av({"ints", "-", "-2"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -439,7 +439,7 @@ TEST_CASE("Integer bounds", "[integer]")
SECTION("No overflow") SECTION("No overflow")
{ {
Argv av({"ints", "--", "127", "-128", "0x7f", "-0x80", "0x7e"}); Argv av({"ints", "-", "127", "-128", "0x7f", "-0x80", "0x7e"});
auto argv = av.argv(); auto argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -481,7 +481,7 @@ TEST_CASE("Integer overflow", "[options]")
options.add_options() options.add_options()
("positional", "Integers", cxxopts::value<std::vector<int8_t>>()); ("positional", "Integers", cxxopts::value<std::vector<int8_t>>());
Argv av({"ints", "--", "128"}); Argv av({"ints", "-", "128"});
auto argv = av.argv(); auto argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -501,7 +501,7 @@ TEST_CASE("Floats", "[options]")
("double", "Double precision", cxxopts::value<double>()) ("double", "Double precision", cxxopts::value<double>())
("positional", "Floats", cxxopts::value<std::vector<float>>()); ("positional", "Floats", cxxopts::value<std::vector<float>>());
Argv av({"floats", "--double", "0.5", "--", "4", "-4", "1.5e6", "-1.5e6"}); Argv av({"floats", "-double", "0.5", "-", "4", "-4", "1.5e6", "-1.5e6"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -526,7 +526,7 @@ TEST_CASE("Invalid integers", "[integer]") {
options.add_options() options.add_options()
("positional", "Integers", cxxopts::value<std::vector<int>>()); ("positional", "Integers", cxxopts::value<std::vector<int>>());
Argv av({"ints", "--", "Ae"}); Argv av({"ints", "-", "Ae"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -551,7 +551,7 @@ TEST_CASE("Booleans", "[boolean]") {
options.parse_positional("others"); options.parse_positional("others");
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"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -585,7 +585,7 @@ TEST_CASE("std::vector", "[vector]") {
options.add_options() options.add_options()
("vector", "an vector option", cxxopts::value<std::vector<double>>(vector)); ("vector", "an vector option", cxxopts::value<std::vector<double>>(vector));
Argv av({"vector", "--vector", "1,-2.1,3,4.5"}); Argv av({"vector", "-vector", "1,-2.1,3,4.5"});
auto** argv = av.argv(); auto** argv = av.argv();
auto argc = av.argc(); auto argc = av.argc();
@ -622,15 +622,13 @@ TEST_CASE("Unrecognised options", "[options]") {
cxxopts::Options options("unknown_options", " - test unknown options"); cxxopts::Options options("unknown_options", " - test unknown options");
options.add_options() options.add_options()
("long", "a long option") ("long", "a long option");
("s,short", "a short option");
Argv av({ Argv av({
"unknown_options", "unknown_options",
"--unknown", "-unknown",
"--long", "-long",
"-su", "-another_unknown",
"--another_unknown",
}); });
auto** argv = av.argv(); auto** argv = av.argv();
@ -644,36 +642,10 @@ TEST_CASE("Unrecognised options", "[options]") {
options.allow_unrecognised_options(); options.allow_unrecognised_options();
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
auto& unmatched = result.unmatched(); auto& unmatched = result.unmatched();
CHECK((unmatched == std::vector<std::string>{"--unknown", "--another_unknown"})); CHECK((unmatched == std::vector<std::string>{"-unknown", "-another_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",
});
auto** 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]") { TEST_CASE("Invalid option syntax", "[options]") {
cxxopts::Options options("invalid_syntax", " - test invalid syntax"); cxxopts::Options options("invalid_syntax", " - test invalid syntax");
@ -700,7 +672,7 @@ TEST_CASE("Options empty", "[options]") {
Argv argv_({ Argv argv_({
"test", "test",
"--unknown" "-unknown"
}); });
auto argc = argv_.argc(); auto argc = argv_.argc();
auto** argv = argv_.argv(); auto** argv = argv_.argv();
@ -726,7 +698,7 @@ TEST_CASE("Initializer list with group", "[options]") {
Argv argv({ Argv argv({
"test", "test",
"--address", "-address",
"10.0.0.1", "10.0.0.1",
"-p", "-p",
"8000", "8000",
@ -756,7 +728,7 @@ TEST_CASE("Option add with add_option(string, Option)", "[options]") {
Argv argv_({ Argv argv_({
"test", "test",
"--test", "-test",
"5", "5",
"-a", "-a",
"4" "4"