1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-04-30 04:33:53 +00:00

Preparing for regex replacement

This commit is contained in:
Henry Fredrick Schreiner 2017-01-31 16:22:50 -05:00
parent 288c790f54
commit 25d4cbaf04
2 changed files with 114 additions and 18 deletions

View File

@ -4,7 +4,6 @@
// file LICENSE or https://github.com/henryiii/CLI11 for details.
#include <string>
#include <regex>
#include <memory>
#include <deque>
#include <iostream>
@ -24,6 +23,18 @@
#include <sys/types.h>
#include <sys/stat.h>
// GCC 4.7 and 4.8 have an non-working implementation of regex
#include <regex>
#if __cplusplus >= 201103L \
&& (!defined(__GLIBCXX__) \
|| (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE>4) \
|| (__cplusplus >= 201402L) \
|| (defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || defined(_GLIBCXX_REGEX_STATE_LIMIT)))
#define HAVE_WORKING_REGEX 1
#else
#define HAVE_WORKING_REGEX 0
#endif
//#define CLI_LOG 1
namespace CLI {
@ -182,8 +193,30 @@ const std::regex reg_split{R"regex((?:([a-zA-Z_]?)(?:,|$)|^)([a-zA-Z0-9_][a-zA-Z
const std::regex reg_short{R"regex(-([a-zA-Z_])(.*))regex"};
const std::regex reg_long{R"regex(--([^-^=][^=]*)=?(.*))regex"};
// Returns false if not a short option. Otherwise, sets opt name and rest and returns true
inline bool split_short(const std::string &current, std::string &name, std::string &rest) {
std::smatch match;
if(std::regex_match(current, match, reg_short)) {
name = match[1];
rest = match[2];
return true;
} else
return false;
}
std::tuple<std::string, std::string> split(std::string fullname) {
// Returns false if not a long option. Otherwise, sets opt name and other side of = and returns true
inline bool split_long(const std::string &current, std::string &name, std::string &value) {
std::smatch match;
if(std::regex_match(current, match, reg_long)) {
name = match[1];
value = match[2];
return true;
} else
return false;
}
// Splits a string into long and short names
inline std::tuple<std::string, std::string> split(std::string fullname) {
std::smatch match;
if (std::regex_match(fullname, match, reg_split)) {
@ -195,6 +228,19 @@ std::tuple<std::string, std::string> split(std::string fullname) {
} else throw BadNameString(fullname);
}
// Splits a string into multiple long and short names (not implemented)
inline std::vector<std::string> split_names(std::string current) {
std::vector<std::string> output;
size_t val;
while((val = current.find(",")) != std::string::npos) {
output.push_back(current.substr(0,val));
current = current.substr(val+1);
}
output.push_back(current);
return output;
}
const Combiner NOTHING {0, false,false,false, {}};
const Combiner REQUIRED {1, false,true, false, {}};
const Combiner DEFAULT {1, false,false,true, {}};
@ -843,14 +889,12 @@ public:
void _parse_short(std::vector<std::string> &args) {
std::string current = args.back();
std::smatch match;
if(!std::regex_match(current, match, reg_short))
std::string name;
std::string rest;
if(!split_short(current, name, rest))
throw HorribleError("Short");
args.pop_back();
std::string name = match[1];
std::string rest = match[2];
logit("Working on short: " + name + " (" + rest + ")");
@ -895,31 +939,29 @@ public:
}
Classifer _recognize(std::string current) const {
std::string dummy1, dummy2;
if(current == "--")
return Classifer::POSITIONAL_MARK;
for(const std::unique_ptr<App> &com : subcommands) {
if(com->name == current)
return Classifer::SUBCOMMAND;
}
if(std::regex_match(current, reg_long))
if(split_long(current, dummy1, dummy2))
return Classifer::LONG;
if(std::regex_match(current, reg_short))
if(split_short(current, dummy1, dummy2))
return Classifer::SHORT;
return Classifer::NONE;
}
void _parse_long(std::vector<std::string> &args) {
std::string current = args.back();
std::smatch match;
if(!std::regex_match(current, match, reg_long))
std::string name;
std::string value;
if(!split_long(current, name, value))
throw HorribleError("Long");
args.pop_back();
std::string name = match[1];
std::string value = match[2];
logit("Working on long: " + name + " (" + value + ")");

View File

@ -5,8 +5,6 @@
TEST(Split, GoodStrings) {
std::vector<std::string> test_strings = {"a,boo", ",coo", "d,", "Q,this-is", "s", "single"};
std::string s, l;
std::tie(s, l) = CLI::split("a,boo");
@ -65,3 +63,59 @@ TEST(Validators, FileNotExists) {
std::remove(myfile.c_str());
EXPECT_TRUE(CLI::_NonexistentPath(myfile));
}
TEST(Split, StringList) {
std::vector<std::string> results {"a", "long", "--lone", "-q"};
EXPECT_EQ(results, CLI::split_names("a,long,--lone,-q"));
EXPECT_EQ(std::vector<std::string>({"one"}), CLI::split_names("one"));
}
TEST(RegEx, Shorts) {
std::string name, value;
EXPECT_TRUE(CLI::split_short("-a", name, value));
EXPECT_EQ("a", name);
EXPECT_EQ("", value);
EXPECT_TRUE(CLI::split_short("-B", name, value));
EXPECT_EQ("B", name);
EXPECT_EQ("", value);
EXPECT_TRUE(CLI::split_short("-cc", name, value));
EXPECT_EQ("c", name);
EXPECT_EQ("c", value);
EXPECT_TRUE(CLI::split_short("-simple", name, value));
EXPECT_EQ("s", name);
EXPECT_EQ("imple", value);
EXPECT_FALSE(CLI::split_short("--a", name, value));
EXPECT_FALSE(CLI::split_short("--thing", name, value));
EXPECT_FALSE(CLI::split_short("--", name, value));
EXPECT_FALSE(CLI::split_short("something", name, value));
EXPECT_FALSE(CLI::split_short("s", name, value));
}
TEST(RegEx, Longs) {
std::string name, value;
EXPECT_TRUE(CLI::split_long("--a", name, value));
EXPECT_EQ("a", name);
EXPECT_EQ("", value);
EXPECT_TRUE(CLI::split_long("--thing", name, value));
EXPECT_EQ("thing", name);
EXPECT_EQ("", value);
EXPECT_TRUE(CLI::split_long("--some=thing", name, value));
EXPECT_EQ("some", name);
EXPECT_EQ("thing", value);
EXPECT_FALSE(CLI::split_long("-a", name, value));
EXPECT_FALSE(CLI::split_long("-things", name, value));
EXPECT_FALSE(CLI::split_long("Q", name, value));
EXPECT_FALSE(CLI::split_long("--", name, value));
}