我修改了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
Permission is hereby granted, free of charge, to any person obtaining a copy
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
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
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,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef CXXOPTS_HPP_INCLUDED
@ -665,7 +661,7 @@ namespace cxxopts
void stringstream_parser(const std::string& text, T& value)
{
std::stringstream in(text);
in >> value;
in >> value; //!!!!niubi!
if (!in) {
throw_or_mimic<argument_incorrect_type>(text);
}
@ -778,7 +774,6 @@ namespace cxxopts
value.emplace_back(std::move(v));
}
}
#ifdef CXXOPTS_HAS_OPTIONAL
template <typename T>
void
@ -1580,7 +1575,7 @@ namespace cxxopts
constexpr size_t OPTION_DESC_GAP = 2;
std::basic_regex<char> option_matcher
("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
("-([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]{1})(=(.*))?");
std::basic_regex<char> option_specifier
("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
@ -1843,7 +1838,7 @@ inline
void
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()];
store.parse_default(details);
}
@ -1980,7 +1975,7 @@ OptionParser::parse(int argc, const char* const* argv)
while (current != argc)
{
if (strcmp(argv[current], "--") == 0)
if (strcmp(argv[current], "-") == 0)
{
consume_remaining = true;
++current;
@ -2018,38 +2013,21 @@ OptionParser::parse(int argc, const char* const* argv)
if (result[4].length() != 0)
{
const std::string& s = result[4];
for (std::size_t i = 0; i != s.size(); ++i)
{
std::string name(1, s[i]);
auto iter = m_options.find(name);
if (iter == m_options.end())
{
if (m_allow_unrecognised)
{
auto iter = m_options.find(s);
if(iter==m_options.end()){
if(!m_allow_unrecognised){
throw_or_mimic<option_not_exists_exception>(s);
}
++current;
continue;
}
//error
throw_or_mimic<option_not_exists_exception>(name);
}
auto value = iter->second;
if (i + 1 == s.size())
{
//it must be the last argument
checked_parse_arg(argc, argv, current, value, name);
}
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);
}
if(result[5].length()!=0){
parse_option(value,s,result[6]);
std::cout<<"The value is"<<result[6].str()<<std::endl;
}else{
checked_parse_arg(argc,argv,current,value,s);
}
}
else if (result[1].length() != 0)
@ -2077,7 +2055,6 @@ OptionParser::parse(int argc, const char* const* argv)
if (result[2].length() != 0)
{
//parse the option given
parse_option(opt, name, result[3]);
}
else
@ -2088,7 +2065,6 @@ OptionParser::parse(int argc, const char* const* argv)
}
}
++current;
}
@ -2382,3 +2358,4 @@ Options::group_help(const std::string& group) const
} // namespace cxxopts
#endif //CXXOPTS_HPP_INCLUDED

View File

@ -1,171 +1,57 @@
/*
Copyright (c) 2014 Jarryd Beck
Permission is hereby granted, free of charge, to any person obtaining a copy
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
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
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.
*/
#include<cxxopts.hpp>
#include<iostream>
#include<vector>
using namespace std;
#include "cxxopts.hpp"
void parse(int argc,const char* argv[]){
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"});
try{
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");
auto result = options.parse(argc,argv);
if (result.count("help"))
{
std::cout << options.help({"", "Group"}) << std::endl;
if(result.count("help")){
cout<<options.help({"MyOption"})<<endl;
exit(0);
}
if (apple)
{
std::cout << "Saw option a " << result.count("a") << " times " <<
std::endl;
if(result.count("i")){
cout<<"Saw the argument of int "<<result.count("i")<<" times"<<endl;
cout<<"The last value is "<<result["i"].as<int>()<<endl;
}
if (result.count("b"))
{
std::cout << "Saw option b" << std::endl;
if(result.count("f")){
cout<<"Saw the argument of float "<<result.count("f")<<" times"<<endl;
cout<<"The last value is "<<result["f"].as<float>()<<endl;
}
if (result.count("char"))
{
std::cout << "Saw a character " << result["char"].as<char>() << "" << std::endl;
if(result.count("l")){
auto list = result["l"].as<vector<float>>();
for(auto data:list){
cout<<data<<" ";
}
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;
cout<<endl;
}
auto unmatched = result.unmatched();
for(auto data:unmatched){
cout<<data<<" ";
}
cout<<endl;
}catch (cxxopts::OptionException &e){
e.what();
}
}
if (result.count("input"))
{
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;
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;
}

View File

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