Commit 25d4cbaf044553cd16a2324b4b4fff409aec1af8
1 parent
288c790f
Preparing for regex replacement
Showing
2 changed files
with
114 additions
and
18 deletions
include/CLI.hpp
| @@ -4,7 +4,6 @@ | @@ -4,7 +4,6 @@ | ||
| 4 | // file LICENSE or https://github.com/henryiii/CLI11 for details. | 4 | // file LICENSE or https://github.com/henryiii/CLI11 for details. |
| 5 | 5 | ||
| 6 | #include <string> | 6 | #include <string> |
| 7 | -#include <regex> | ||
| 8 | #include <memory> | 7 | #include <memory> |
| 9 | #include <deque> | 8 | #include <deque> |
| 10 | #include <iostream> | 9 | #include <iostream> |
| @@ -24,6 +23,18 @@ | @@ -24,6 +23,18 @@ | ||
| 24 | #include <sys/types.h> | 23 | #include <sys/types.h> |
| 25 | #include <sys/stat.h> | 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 | //#define CLI_LOG 1 | 38 | //#define CLI_LOG 1 |
| 28 | 39 | ||
| 29 | namespace CLI { | 40 | namespace CLI { |
| @@ -182,8 +193,30 @@ const std::regex reg_split{R"regex((?:([a-zA-Z_]?)(?:,|$)|^)([a-zA-Z0-9_][a-zA-Z | @@ -182,8 +193,30 @@ const std::regex reg_split{R"regex((?:([a-zA-Z_]?)(?:,|$)|^)([a-zA-Z0-9_][a-zA-Z | ||
| 182 | const std::regex reg_short{R"regex(-([a-zA-Z_])(.*))regex"}; | 193 | const std::regex reg_short{R"regex(-([a-zA-Z_])(.*))regex"}; |
| 183 | const std::regex reg_long{R"regex(--([^-^=][^=]*)=?(.*))regex"}; | 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 ¤t, 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 ¤t, 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 | std::smatch match; | 221 | std::smatch match; |
| 189 | if (std::regex_match(fullname, match, reg_split)) { | 222 | if (std::regex_match(fullname, match, reg_split)) { |
| @@ -195,6 +228,19 @@ std::tuple<std::string, std::string> split(std::string fullname) { | @@ -195,6 +228,19 @@ std::tuple<std::string, std::string> split(std::string fullname) { | ||
| 195 | } else throw BadNameString(fullname); | 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 | const Combiner NOTHING {0, false,false,false, {}}; | 244 | const Combiner NOTHING {0, false,false,false, {}}; |
| 199 | const Combiner REQUIRED {1, false,true, false, {}}; | 245 | const Combiner REQUIRED {1, false,true, false, {}}; |
| 200 | const Combiner DEFAULT {1, false,false,true, {}}; | 246 | const Combiner DEFAULT {1, false,false,true, {}}; |
| @@ -843,14 +889,12 @@ public: | @@ -843,14 +889,12 @@ public: | ||
| 843 | 889 | ||
| 844 | void _parse_short(std::vector<std::string> &args) { | 890 | void _parse_short(std::vector<std::string> &args) { |
| 845 | std::string current = args.back(); | 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 | throw HorribleError("Short"); | 896 | throw HorribleError("Short"); |
| 850 | - | ||
| 851 | args.pop_back(); | 897 | args.pop_back(); |
| 852 | - std::string name = match[1]; | ||
| 853 | - std::string rest = match[2]; | ||
| 854 | 898 | ||
| 855 | logit("Working on short: " + name + " (" + rest + ")"); | 899 | logit("Working on short: " + name + " (" + rest + ")"); |
| 856 | 900 | ||
| @@ -895,31 +939,29 @@ public: | @@ -895,31 +939,29 @@ public: | ||
| 895 | } | 939 | } |
| 896 | 940 | ||
| 897 | Classifer _recognize(std::string current) const { | 941 | Classifer _recognize(std::string current) const { |
| 942 | + std::string dummy1, dummy2; | ||
| 943 | + | ||
| 898 | if(current == "--") | 944 | if(current == "--") |
| 899 | return Classifer::POSITIONAL_MARK; | 945 | return Classifer::POSITIONAL_MARK; |
| 900 | for(const std::unique_ptr<App> &com : subcommands) { | 946 | for(const std::unique_ptr<App> &com : subcommands) { |
| 901 | if(com->name == current) | 947 | if(com->name == current) |
| 902 | return Classifer::SUBCOMMAND; | 948 | return Classifer::SUBCOMMAND; |
| 903 | } | 949 | } |
| 904 | - if(std::regex_match(current, reg_long)) | 950 | + if(split_long(current, dummy1, dummy2)) |
| 905 | return Classifer::LONG; | 951 | return Classifer::LONG; |
| 906 | - if(std::regex_match(current, reg_short)) | 952 | + if(split_short(current, dummy1, dummy2)) |
| 907 | return Classifer::SHORT; | 953 | return Classifer::SHORT; |
| 908 | return Classifer::NONE; | 954 | return Classifer::NONE; |
| 909 | - | ||
| 910 | - | ||
| 911 | } | 955 | } |
| 912 | 956 | ||
| 913 | void _parse_long(std::vector<std::string> &args) { | 957 | void _parse_long(std::vector<std::string> &args) { |
| 914 | std::string current = args.back(); | 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 | throw HorribleError("Long"); | 963 | throw HorribleError("Long"); |
| 919 | - | ||
| 920 | args.pop_back(); | 964 | args.pop_back(); |
| 921 | - std::string name = match[1]; | ||
| 922 | - std::string value = match[2]; | ||
| 923 | 965 | ||
| 924 | 966 | ||
| 925 | logit("Working on long: " + name + " (" + value + ")"); | 967 | logit("Working on long: " + name + " (" + value + ")"); |
tests/SmallTest.cpp
| @@ -5,8 +5,6 @@ | @@ -5,8 +5,6 @@ | ||
| 5 | 5 | ||
| 6 | 6 | ||
| 7 | TEST(Split, GoodStrings) { | 7 | TEST(Split, GoodStrings) { |
| 8 | - std::vector<std::string> test_strings = {"a,boo", ",coo", "d,", "Q,this-is", "s", "single"}; | ||
| 9 | - | ||
| 10 | std::string s, l; | 8 | std::string s, l; |
| 11 | 9 | ||
| 12 | std::tie(s, l) = CLI::split("a,boo"); | 10 | std::tie(s, l) = CLI::split("a,boo"); |
| @@ -65,3 +63,59 @@ TEST(Validators, FileNotExists) { | @@ -65,3 +63,59 @@ TEST(Validators, FileNotExists) { | ||
| 65 | std::remove(myfile.c_str()); | 63 | std::remove(myfile.c_str()); |
| 66 | EXPECT_TRUE(CLI::_NonexistentPath(myfile)); | 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 | +} |