diff --git a/include/CLI.hpp b/include/CLI.hpp index 806a31aa..007fb5f7 100644 --- a/include/CLI.hpp +++ b/include/CLI.hpp @@ -287,34 +287,6 @@ inline void cleanup_names(const std::vector &input) { } } -// Splits a string into long and short names -inline std::tuple split(std::string fullname) { - if(fullname.find(" ") != std::string::npos) - throw BadNameString("Cannot have space in name string: "+fullname); - std::vector output = split_names(fullname); - cleanup_names(output); - - if(output.size() > 2) - throw BadNameString(fullname); - else if (output.size() == 2) { - if(output[0].length()==0 && output[1].length()==0) - throw BadNameString("EMPTY"); - else if(output[0].length()<2) - return std::tuple(output[0], output[1]); - else if(output[1].length() < 2) - return std::tuple(output[0], output[1]); - else - throw BadNameString(fullname); - } else { - if(output[0].length()==0) - throw BadNameString("EMPTY"); - else if(output[0].length() == 1) - return std::tuple(output[0], ""); - else - return std::tuple("", output[0]); - } -} - const Combiner NOTHING {0, false,false,false, {}}; const Combiner REQUIRED {1, false,true, false, {}}; @@ -339,8 +311,8 @@ class Option { public: protected: // Config - std::string sname; - std::string lname; + std::vector snames; + std::vector lnames; Combiner opts; std::string discription; callback_t callback; @@ -352,7 +324,7 @@ protected: public: Option(std::string name, std::string discription = "", Combiner opts=NOTHING, std::function callback=[](results_t){return true;}) : opts(opts), discription(discription), callback(callback){ - std::tie(sname, lname) = split(name); + std::tie(snames, lnames) = get_names(split_names(name)); } void clear() { @@ -386,44 +358,44 @@ public: return callback(results); } - /// Indistinguishible options are equal + /// If options share any of the same names, they are equal bool operator== (const Option& other) const { - if(sname=="" && other.sname=="") - return lname==other.lname; - else if(lname=="" && other.lname=="") - return sname==other.sname; - else - return sname==other.sname || lname==other.lname; + for(const std::string &sname : snames) + for(const std::string &othersname : other.snames) + if(sname == othersname) + return true; + for(const std::string &lname : lnames) + for(const std::string &otherlname : other.lnames) + if(lname == otherlname) + return true; + return false; } std::string get_name() const { - if(sname=="") - return "--" + lname; - else if (lname=="") - return "-" + sname; - else - return "-" + sname + ", --" + lname; + std::vector name_list; + for(const std::string& sname : snames) + name_list.push_back("-"+sname); + for(const std::string& lname : lnames) + name_list.push_back("--"+lname); + return join(name_list); } - bool check_name(const std::string& name) const { - return name == sname || name == lname || name == sname + "," + lname; + bool check_name(std::string name) const { + for(int i=0; i<2; i++) + if(name.length()>2 && name[0] == '-') + name = name.substr(1); + + return check_sname(name) || check_lname(name); } bool check_sname(const std::string& name) const { - return name == sname; + return std::find(std::begin(snames), std::end(snames), name) != std::end(snames); } bool check_lname(const std::string& name) const { - return name == lname; + return std::find(std::begin(lnames), std::end(lnames), name) != std::end(lnames); } - std::string get_sname() const { - return sname; - } - - std::string get_lname() const { - return lname; - } void add_result(int r, std::string s) { logit("Adding result: " + s); @@ -976,7 +948,7 @@ public: auto op = std::find_if(std::begin(options), std::end(options), [name](const Option &v){return v.check_sname(name);}); if(op == std::end(options)) { - missing_options.push_back("-" + op->get_sname()); + missing_options.push_back("-" + name); return; } @@ -1044,7 +1016,7 @@ public: auto op = std::find_if(std::begin(options), std::end(options), [name](const Option &v){return v.check_lname(name);}); if(op == std::end(options)) { - missing_options.push_back("--" + op->get_lname()); + missing_options.push_back("--" + name); return; } diff --git a/tests/CLITest.cpp b/tests/CLITest.cpp index ec2396a9..a649fb8e 100644 --- a/tests/CLITest.cpp +++ b/tests/CLITest.cpp @@ -52,6 +52,21 @@ TEST_F(TApp, OneFlagLong) { EXPECT_EQ(1, app.count("count")); } +TEST_F(TApp, DashedOptions) { + app.add_flag("-c"); + app.add_flag("--q"); + app.add_flag("--this,--that"); + + args = {"-c", "--q", "--this", "--that"}; + EXPECT_NO_THROW(run()); + EXPECT_EQ(1, app.count("c")); + EXPECT_EQ(1, app.count("q")); + EXPECT_EQ(2, app.count("this")); + EXPECT_EQ(2, app.count("--that")); + +} + + TEST_F(TApp, OneFlagRef) { int ref; app.add_flag("c,count", ref); @@ -454,9 +469,6 @@ TEST_F(TAppValue, DoubleVector) { EXPECT_EQ(std::vector({1.2, 3.4, -1}), *value); } -// TODO: Maybe add function to call on subcommand parse? Stashed. // TODO: Check help output, better formatting // TODO: Add default/type info to help -// TODO: Add regex replacement function (GCC 4.8 support) // TODO: Add README -// TODO: Change format of option specifications? diff --git a/tests/SmallTest.cpp b/tests/SmallTest.cpp index 69cbf789..5ca11c51 100644 --- a/tests/SmallTest.cpp +++ b/tests/SmallTest.cpp @@ -4,44 +4,6 @@ #include -TEST(Split, GoodStrings) { - std::string s, l; - - std::tie(s, l) = CLI::split("a,boo"); - EXPECT_EQ("a", s); - EXPECT_EQ("boo", l); - - std::tie(s, l) = CLI::split(",coo"); - EXPECT_EQ("", s); - EXPECT_EQ("coo", l); - - std::tie(s, l) = CLI::split("d,"); - EXPECT_EQ("d", s); - EXPECT_EQ("", l); - - std::tie(s, l) = CLI::split("Q,this-is"); - EXPECT_EQ("Q", s); - EXPECT_EQ("this-is", l); - - std::tie(s, l) = CLI::split("s"); - EXPECT_EQ("s", s); - EXPECT_EQ("", l); - - std::tie(s, l) = CLI::split("single"); - EXPECT_EQ("", s); - EXPECT_EQ("single", l); - } - -TEST(Split, BadStrings) { - - EXPECT_THROW(CLI::split("a,,boo"), CLI::BadNameString); - EXPECT_THROW(CLI::split("a,b,c"), CLI::BadNameString); - EXPECT_THROW(CLI::split("ssd,sfd"), CLI::BadNameString); - EXPECT_THROW(CLI::split("-a"), CLI::BadNameString); - EXPECT_THROW(CLI::split(""), CLI::BadNameString); - EXPECT_THROW(CLI::split(","), CLI::BadNameString); - EXPECT_THROW(CLI::split("one two"), CLI::BadNameString); -} TEST(Validators, FileExists) { std::string myfile{"TestFileNotUsed.txt"};