Commit 87be1a3e389f80452886237d1e487195600db6e0

Authored by Henry Fredrick Schreiner
1 parent 4dd29333

Adding nicer name splitter

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&lt;std::string&gt; 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 +}
... ...