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,6 +23,8 @@ | ||
| 23 | #include <sys/types.h> | 23 | #include <sys/types.h> |
| 24 | #include <sys/stat.h> | 24 | #include <sys/stat.h> |
| 25 | 25 | ||
| 26 | +#include <locale> | ||
| 27 | + | ||
| 26 | // GCC 4.7 and 4.8 have an non-working implementation of regex | 28 | // GCC 4.7 and 4.8 have an non-working implementation of regex |
| 27 | #include <regex> | 29 | #include <regex> |
| 28 | #if __cplusplus >= 201103L \ | 30 | #if __cplusplus >= 201103L \ |
| @@ -227,6 +229,58 @@ inline std::vector<std::string> split_names(std::string current) { | @@ -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 | // Currently just throws an error if name is incorrect. May clean later. | 284 | // Currently just throws an error if name is incorrect. May clean later. |
| 231 | inline void cleanup_names(const std::vector<std::string> &input) { | 285 | inline void cleanup_names(const std::vector<std::string> &input) { |
| 232 | 286 |
tests/SmallTest.cpp
| @@ -120,3 +120,22 @@ TEST(RegEx, Longs) { | @@ -120,3 +120,22 @@ TEST(RegEx, Longs) { | ||
| 120 | EXPECT_FALSE(CLI::split_long("--", name, value)); | 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 | +} |