Commit 25d4cbaf044553cd16a2324b4b4fff409aec1af8

Authored by Henry Fredrick Schreiner
1 parent 288c790f

Preparing for regex replacement

include/CLI.hpp
... ... @@ -4,7 +4,6 @@
4 4 // file LICENSE or https://github.com/henryiii/CLI11 for details.
5 5  
6 6 #include <string>
7   -#include <regex>
8 7 #include <memory>
9 8 #include <deque>
10 9 #include <iostream>
... ... @@ -24,6 +23,18 @@
24 23 #include <sys/types.h>
25 24 #include <sys/stat.h>
26 25  
  26 +// GCC 4.7 and 4.8 have an non-working implementation of regex
  27 +#include <regex>
  28 +#if __cplusplus >= 201103L \
  29 + && (!defined(__GLIBCXX__) \
  30 + || (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE>4) \
  31 + || (__cplusplus >= 201402L) \
  32 + || (defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || defined(_GLIBCXX_REGEX_STATE_LIMIT)))
  33 +#define HAVE_WORKING_REGEX 1
  34 +#else
  35 +#define HAVE_WORKING_REGEX 0
  36 +#endif
  37 +
27 38 //#define CLI_LOG 1
28 39  
29 40 namespace CLI {
... ... @@ -182,8 +193,30 @@ const std::regex reg_split{R&quot;regex((?:([a-zA-Z_]?)(?:,|$)|^)([a-zA-Z0-9_][a-zA-Z
182 193 const std::regex reg_short{R"regex(-([a-zA-Z_])(.*))regex"};
183 194 const std::regex reg_long{R"regex(--([^-^=][^=]*)=?(.*))regex"};
184 195  
  196 +// Returns false if not a short option. Otherwise, sets opt name and rest and returns true
  197 +inline bool split_short(const std::string &current, std::string &name, std::string &rest) {
  198 + std::smatch match;
  199 + if(std::regex_match(current, match, reg_short)) {
  200 + name = match[1];
  201 + rest = match[2];
  202 + return true;
  203 + } else
  204 + return false;
  205 +}
  206 +
  207 +// Returns false if not a long option. Otherwise, sets opt name and other side of = and returns true
  208 +inline bool split_long(const std::string &current, std::string &name, std::string &value) {
  209 + std::smatch match;
  210 + if(std::regex_match(current, match, reg_long)) {
  211 + name = match[1];
  212 + value = match[2];
  213 + return true;
  214 + } else
  215 + return false;
  216 +}
185 217  
186   -std::tuple<std::string, std::string> split(std::string fullname) {
  218 +// Splits a string into long and short names
  219 +inline std::tuple<std::string, std::string> split(std::string fullname) {
187 220  
188 221 std::smatch match;
189 222 if (std::regex_match(fullname, match, reg_split)) {
... ... @@ -195,6 +228,19 @@ std::tuple&lt;std::string, std::string&gt; split(std::string fullname) {
195 228 } else throw BadNameString(fullname);
196 229 }
197 230  
  231 +// Splits a string into multiple long and short names (not implemented)
  232 +inline std::vector<std::string> split_names(std::string current) {
  233 + std::vector<std::string> output;
  234 + size_t val;
  235 + while((val = current.find(",")) != std::string::npos) {
  236 + output.push_back(current.substr(0,val));
  237 + current = current.substr(val+1);
  238 + }
  239 + output.push_back(current);
  240 + return output;
  241 +
  242 +}
  243 +
198 244 const Combiner NOTHING {0, false,false,false, {}};
199 245 const Combiner REQUIRED {1, false,true, false, {}};
200 246 const Combiner DEFAULT {1, false,false,true, {}};
... ... @@ -843,14 +889,12 @@ public:
843 889  
844 890 void _parse_short(std::vector<std::string> &args) {
845 891 std::string current = args.back();
846   - std::smatch match;
847 892  
848   - if(!std::regex_match(current, match, reg_short))
  893 + std::string name;
  894 + std::string rest;
  895 + if(!split_short(current, name, rest))
849 896 throw HorribleError("Short");
850   -
851 897 args.pop_back();
852   - std::string name = match[1];
853   - std::string rest = match[2];
854 898  
855 899 logit("Working on short: " + name + " (" + rest + ")");
856 900  
... ... @@ -895,31 +939,29 @@ public:
895 939 }
896 940  
897 941 Classifer _recognize(std::string current) const {
  942 + std::string dummy1, dummy2;
  943 +
898 944 if(current == "--")
899 945 return Classifer::POSITIONAL_MARK;
900 946 for(const std::unique_ptr<App> &com : subcommands) {
901 947 if(com->name == current)
902 948 return Classifer::SUBCOMMAND;
903 949 }
904   - if(std::regex_match(current, reg_long))
  950 + if(split_long(current, dummy1, dummy2))
905 951 return Classifer::LONG;
906   - if(std::regex_match(current, reg_short))
  952 + if(split_short(current, dummy1, dummy2))
907 953 return Classifer::SHORT;
908 954 return Classifer::NONE;
909   -
910   -
911 955 }
912 956  
913 957 void _parse_long(std::vector<std::string> &args) {
914 958 std::string current = args.back();
915   - std::smatch match;
916 959  
917   - if(!std::regex_match(current, match, reg_long))
  960 + std::string name;
  961 + std::string value;
  962 + if(!split_long(current, name, value))
918 963 throw HorribleError("Long");
919   -
920 964 args.pop_back();
921   - std::string name = match[1];
922   - std::string value = match[2];
923 965  
924 966  
925 967 logit("Working on long: " + name + " (" + value + ")");
... ...
tests/SmallTest.cpp
... ... @@ -5,8 +5,6 @@
5 5  
6 6  
7 7 TEST(Split, GoodStrings) {
8   - std::vector<std::string> test_strings = {"a,boo", ",coo", "d,", "Q,this-is", "s", "single"};
9   -
10 8 std::string s, l;
11 9  
12 10 std::tie(s, l) = CLI::split("a,boo");
... ... @@ -65,3 +63,59 @@ TEST(Validators, FileNotExists) {
65 63 std::remove(myfile.c_str());
66 64 EXPECT_TRUE(CLI::_NonexistentPath(myfile));
67 65 }
  66 +
  67 +TEST(Split, StringList) {
  68 +
  69 + std::vector<std::string> results {"a", "long", "--lone", "-q"};
  70 + EXPECT_EQ(results, CLI::split_names("a,long,--lone,-q"));
  71 +
  72 + EXPECT_EQ(std::vector<std::string>({"one"}), CLI::split_names("one"));
  73 +}
  74 +
  75 +TEST(RegEx, Shorts) {
  76 + std::string name, value;
  77 +
  78 + EXPECT_TRUE(CLI::split_short("-a", name, value));
  79 + EXPECT_EQ("a", name);
  80 + EXPECT_EQ("", value);
  81 +
  82 + EXPECT_TRUE(CLI::split_short("-B", name, value));
  83 + EXPECT_EQ("B", name);
  84 + EXPECT_EQ("", value);
  85 +
  86 + EXPECT_TRUE(CLI::split_short("-cc", name, value));
  87 + EXPECT_EQ("c", name);
  88 + EXPECT_EQ("c", value);
  89 +
  90 + EXPECT_TRUE(CLI::split_short("-simple", name, value));
  91 + EXPECT_EQ("s", name);
  92 + EXPECT_EQ("imple", value);
  93 +
  94 + EXPECT_FALSE(CLI::split_short("--a", name, value));
  95 + EXPECT_FALSE(CLI::split_short("--thing", name, value));
  96 + EXPECT_FALSE(CLI::split_short("--", name, value));
  97 + EXPECT_FALSE(CLI::split_short("something", name, value));
  98 + EXPECT_FALSE(CLI::split_short("s", name, value));
  99 +}
  100 +
  101 +TEST(RegEx, Longs) {
  102 + std::string name, value;
  103 +
  104 + EXPECT_TRUE(CLI::split_long("--a", name, value));
  105 + EXPECT_EQ("a", name);
  106 + EXPECT_EQ("", value);
  107 +
  108 + EXPECT_TRUE(CLI::split_long("--thing", name, value));
  109 + EXPECT_EQ("thing", name);
  110 + EXPECT_EQ("", value);
  111 +
  112 + EXPECT_TRUE(CLI::split_long("--some=thing", name, value));
  113 + EXPECT_EQ("some", name);
  114 + EXPECT_EQ("thing", value);
  115 +
  116 + EXPECT_FALSE(CLI::split_long("-a", name, value));
  117 + EXPECT_FALSE(CLI::split_long("-things", name, value));
  118 + EXPECT_FALSE(CLI::split_long("Q", name, value));
  119 + EXPECT_FALSE(CLI::split_long("--", name, value));
  120 +
  121 +}
... ...