Commit 87be1a3e389f80452886237d1e487195600db6e0
1 parent
4dd29333
Adding nicer name splitter
Showing
2 changed files
with
73 additions
and
0 deletions
include/CLI.hpp
| ... | ... | @@ -23,6 +23,8 @@ |
| 23 | 23 | #include <sys/types.h> |
| 24 | 24 | #include <sys/stat.h> |
| 25 | 25 | |
| 26 | +#include <locale> | |
| 27 | + | |
| 26 | 28 | // GCC 4.7 and 4.8 have an non-working implementation of regex |
| 27 | 29 | #include <regex> |
| 28 | 30 | #if __cplusplus >= 201103L \ |
| ... | ... | @@ -227,6 +229,58 @@ inline std::vector<std::string> split_names(std::string current) { |
| 227 | 229 | |
| 228 | 230 | } |
| 229 | 231 | |
| 232 | +template<typename T> | |
| 233 | +bool valid_first_char(T c) { | |
| 234 | + return std::isalpha(c) || c=='_'; | |
| 235 | +} | |
| 236 | + | |
| 237 | +template<typename T> | |
| 238 | +bool valid_later_char(T c) { | |
| 239 | + return std::isalnum(c) || c=='_' || c=='.' || c=='-'; | |
| 240 | +} | |
| 241 | + | |
| 242 | +inline bool valid_name_string(const std::string &str) { | |
| 243 | + if(str.size()<1 || !valid_first_char(str[0])) | |
| 244 | + return false; | |
| 245 | + for(auto c : str.substr(1)) | |
| 246 | + if(!valid_later_char(c)) | |
| 247 | + return false; | |
| 248 | + return true; | |
| 249 | +} | |
| 250 | + | |
| 251 | +inline std::tuple<std::vector<std::string>,std::vector<std::string>> get_names(const std::vector<std::string> &input) { | |
| 252 | + std::vector<std::string> short_names; | |
| 253 | + std::vector<std::string> long_names; | |
| 254 | + | |
| 255 | + for(std::string name : input) { | |
| 256 | + if(name.length() == 0) | |
| 257 | + continue; | |
| 258 | + else if(name.length() == 1) | |
| 259 | + if(valid_first_char(name[0])) | |
| 260 | + short_names.push_back(name); | |
| 261 | + else | |
| 262 | + throw BadNameString("Invalid one char name: "+name); | |
| 263 | + else if(name.length() == 2 && name[0] == '-' && name[1] != '-') { | |
| 264 | + if(valid_first_char(name[1])) | |
| 265 | + short_names.push_back(std::string(1,name[1])); | |
| 266 | + else | |
| 267 | + throw BadNameString("Invalid one char name: "+name); | |
| 268 | + } else { | |
| 269 | + | |
| 270 | + if(name.substr(0,2) == "--") | |
| 271 | + name = name.substr(2); | |
| 272 | + if(valid_name_string(name)) | |
| 273 | + long_names.push_back(name); | |
| 274 | + else | |
| 275 | + throw BadNameString("Bad long name"+name); | |
| 276 | + | |
| 277 | + } | |
| 278 | + } | |
| 279 | + | |
| 280 | + return {short_names, long_names}; | |
| 281 | + | |
| 282 | +} | |
| 283 | + | |
| 230 | 284 | // Currently just throws an error if name is incorrect. May clean later. |
| 231 | 285 | inline void cleanup_names(const std::vector<std::string> &input) { |
| 232 | 286 | ... | ... |
tests/SmallTest.cpp
| ... | ... | @@ -120,3 +120,22 @@ TEST(RegEx, Longs) { |
| 120 | 120 | EXPECT_FALSE(CLI::split_long("--", name, value)); |
| 121 | 121 | |
| 122 | 122 | } |
| 123 | + | |
| 124 | +TEST(Regex, SplittingNew) { | |
| 125 | + | |
| 126 | + std::vector<std::string> shorts; | |
| 127 | + std::vector<std::string> longs; | |
| 128 | + | |
| 129 | + EXPECT_NO_THROW(std::tie(shorts, longs) = CLI::get_names({"--long", "s", "-q", "also-long"})); | |
| 130 | + EXPECT_EQ(std::vector<std::string>({"long", "also-long"}), longs); | |
| 131 | + EXPECT_EQ(std::vector<std::string>({"s", "q"}), shorts); | |
| 132 | + | |
| 133 | + EXPECT_NO_THROW(std::tie(shorts, longs) = CLI::get_names({"--long", "", "s", "-q", "", "also-long"})); | |
| 134 | + EXPECT_EQ(std::vector<std::string>({"long", "also-long"}), longs); | |
| 135 | + EXPECT_EQ(std::vector<std::string>({"s", "q"}), shorts); | |
| 136 | + | |
| 137 | + EXPECT_THROW(std::tie(shorts, longs) = CLI::get_names({"-"}), CLI::BadNameString); | |
| 138 | + EXPECT_THROW(std::tie(shorts, longs) = CLI::get_names({"--"}), CLI::BadNameString); | |
| 139 | + EXPECT_THROW(std::tie(shorts, longs) = CLI::get_names({"-hi"}), CLI::BadNameString); | |
| 140 | + | |
| 141 | +} | ... | ... |