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 | 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"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 ¤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 | 221 | std::smatch match; |
| 189 | 222 | if (std::regex_match(fullname, match, reg_split)) { |
| ... | ... | @@ -195,6 +228,19 @@ std::tuple<std::string, std::string> 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 | +} | ... | ... |