Extract compatibility codes and aggregate them together.

This commit is contained in:
RonxBulld 2021-04-25 00:50:17 +08:00
parent a956948fdd
commit 6e0870addd

View File

@ -43,7 +43,7 @@ THE SOFTWARE.
#if defined(__GNUC__) && !defined(__clang__)
# if (__GNUC__ * 10 + __GNUC_MINOR__) < 49
# define NO_REGEX
# define NO_REGEX true
# endif
#endif
@ -529,17 +529,257 @@ namespace cxxopts
namespace values
{
#ifndef NO_REGEX
namespace
namespace parser_tool
{
std::basic_regex<char> integer_pattern
("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
std::basic_regex<char> truthy_pattern
("(t|T)(rue)?|1");
std::basic_regex<char> falsy_pattern
("(f|F)(alse)?|0");
} // namespace
struct IntegerDesc
{
String negative = "";
String base = "";
String value = "";
};
struct ArguDesc {
String arg_name = "";
bool grouping = false;
bool set_value = false;
String value = "";
};
#ifdef NO_REGEX
inline IntegerDesc SplitInteger(const String &text)
{
if (text.empty())
{
throw_or_mimic<argument_incorrect_type>(text);
}
IntegerDesc desc;
const char *pdata = text.c_str();
if (*pdata == '-')
{
pdata += 1;
desc.negative = "-";
}
if (strncmp(pdata, "0x", 2) == 0)
{
pdata += 2;
desc.base = "0x";
}
if (*pdata != '\0')
{
desc.value = String(pdata);
}
else
{
throw_or_mimic<argument_incorrect_type>(text);
}
return desc;
}
inline bool IsTrueText(const String &text)
{
const char *pdata = text.c_str();
if (*pdata == 't' || *pdata == 'T')
{
pdata += 1;
if (strncmp(pdata, "rue\0", 4) == 0)
{
return true;
}
}
else if (strncmp(pdata, "1\0", 2) == 0)
{
return true;
}
return false;
}
inline bool IsFalseText(const String &text)
{
const char *pdata = text.c_str();
if (*pdata == 'f' || *pdata == 'F')
{
pdata += 1;
if (strncmp(pdata, "alse\0", 5) == 0)
{
return true;
}
}
else if (strncmp(pdata, "0\0", 2) == 0)
{
return true;
}
return false;
}
inline std::pair<String, String> SplitSwitchDef(const String &text)
{
String short_sw, long_sw;
const char *pdata = text.c_str();
if (isalnum(*pdata) && *(pdata + 1) == ',') {
short_sw = String(1, *pdata);
pdata += 2;
}
while (*pdata == ' ') { pdata += 1; }
if (isalnum(*pdata)) {
const char *store = pdata;
pdata += 1;
while (isalnum(*pdata) || *pdata == '-' || *pdata == '_') {
pdata += 1;
}
if (*pdata == '\0') {
long_sw = String(store, pdata - store);
} else {
throw_or_mimic<invalid_option_format_error>(text);
}
}
return std::pair<String, String>(short_sw, long_sw);
}
inline ArguDesc ParseArgument(const char *arg, bool &matched)
{
ArguDesc argu_desc;
const char *pdata = arg;
matched = false;
if (strncmp(pdata, "--", 2) == 0)
{
pdata += 2;
if (isalnum(*pdata))
{
argu_desc.arg_name.push_back(*pdata);
pdata += 1;
while (isalnum(*pdata) || *pdata == '-' || *pdata == '_')
{
argu_desc.arg_name.push_back(*pdata);
pdata += 1;
}
if (argu_desc.arg_name.length() > 1)
{
if (*pdata == '=')
{
argu_desc.set_value = true;
pdata += 1;
if (*pdata != '\0')
{
argu_desc.value = String(pdata);
}
matched = true;
}
else if (*pdata == '\0')
{
matched = true;
}
}
}
}
else if (strncmp(pdata, "-", 1) == 0)
{
pdata += 1;
argu_desc.grouping = true;
while (isalnum(*pdata))
{
argu_desc.arg_name.push_back(*pdata);
pdata += 1;
}
matched = !argu_desc.arg_name.empty() && *pdata == '\0';
}
return argu_desc;
}
#else // NO_REGEX
namespace
{
std::basic_regex<char> integer_pattern
("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
std::basic_regex<char> truthy_pattern
("(t|T)(rue)?|1");
std::basic_regex<char> falsy_pattern
("(f|F)(alse)?|0");
std::basic_regex<char> option_matcher
("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
std::basic_regex<char> option_specifier
("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
} // namespace
inline IntegerDesc SplitInteger(const String &text)
{
std::smatch match;
std::regex_match(text, match, integer_pattern);
if (match.length() == 0)
{
throw_or_mimic<argument_incorrect_type>(text);
}
IntegerDesc desc;
desc.negative = match[1];
desc.base = match[2];
desc.value = match[3];
if (match.length(4) > 0)
{
desc.base = match[5];
desc.value = "0";
return desc;
}
return desc;
}
inline bool IsTrueText(const String &text)
{
std::smatch result;
std::regex_match(text, result, truthy_pattern);
return !result.empty();
}
inline bool IsFalseText(const String &text)
{
std::smatch result;
std::regex_match(text, result, falsy_pattern);
return !result.empty();
}
inline std::pair<String, String> SplitSwitchDef(const String &text)
{
std::match_results<const char*> result;
std::regex_match(text.c_str(), result, option_specifier);
if (result.empty())
{
throw_or_mimic<invalid_option_format_error>(text);
}
const String& short_sw = result[2];
const String& long_sw = result[3];
return std::pair<String, String>(short_sw, long_sw);
}
inline ArguDesc ParseArgument(const char *arg, bool &matched)
{
std::match_results<const char*> result;
std::regex_match(arg, result, option_matcher);
matched = !result.empty();
ArguDesc argu_desc;
if (matched) {
argu_desc.arg_name = result[1].str();
argu_desc.set_value = result[2].length() > 0;
argu_desc.value = result[3].str();
if (result[4].length() > 0)
{
argu_desc.grouping = true;
argu_desc.arg_name = result[4].str();
}
}
return argu_desc;
}
#endif // NO_REGEX
#undef NO_REGEX
}
namespace detail
{
@ -607,76 +847,32 @@ namespace cxxopts
void
integer_parser(const std::string& text, T& value)
{
#ifdef NO_REGEX
if (text.empty()) {
throw_or_mimic<argument_incorrect_type>(text);
}
String part[3];
const char *pdata = text.c_str();
if (*pdata == '-') {
pdata += 1;
part[0] = "-";
}
if (strncmp(pdata, "0x", 2) == 0) {
pdata += 2;
part[1] = "0x";
}
if (*pdata != '\0') {
part[2] = String(pdata);
} else {
throw_or_mimic<argument_incorrect_type>(text);
}
parser_tool::IntegerDesc int_desc = parser_tool::SplitInteger(text);
using US = typename std::make_unsigned<T>::type;
constexpr bool is_signed = std::numeric_limits<T>::is_signed;
const bool negative = part[0].length() > 0;
const uint8_t base = part[1].length() > 0 ? 16 : 10;
String value_match = part[2];
auto begin_it = value_match.begin();
auto end_it = value_match.end();
#else
std::smatch match;
std::regex_match(text, match, integer_pattern);
if (match.length() == 0)
{
throw_or_mimic<argument_incorrect_type>(text);
}
if (match.length(4) > 0)
{
value = 0;
return;
}
using US = typename std::make_unsigned<T>::type;
constexpr bool is_signed = std::numeric_limits<T>::is_signed;
const bool negative = match.length(1) > 0;
const uint8_t base = match.length(2) > 0 ? 16 : 10;
auto value_match = match[3];
auto &begin_it = value_match.first;
auto &end_it = value_match.second;
#endif // NO_REGEX
const bool negative = int_desc.negative.length() > 0;
const uint8_t base = int_desc.base.length() > 0 ? 16 : 10;
const String & value_match = int_desc.value;
US result = 0;
for (auto iter = begin_it; iter != end_it; ++iter)
for (char ch : value_match)
{
US digit = 0;
if (*iter >= '0' && *iter <= '9')
if (ch >= '0' && ch <= '9')
{
digit = static_cast<US>(*iter - '0');
digit = static_cast<US>(ch - '0');
}
else if (base == 16 && *iter >= 'a' && *iter <= 'f')
else if (base == 16 && ch >= 'a' && ch <= 'f')
{
digit = static_cast<US>(*iter - 'a' + 10);
digit = static_cast<US>(ch - 'a' + 10);
}
else if (base == 16 && *iter >= 'A' && *iter <= 'F')
else if (base == 16 && ch >= 'A' && ch <= 'F')
{
digit = static_cast<US>(*iter - 'A' + 10);
digit = static_cast<US>(ch - 'A' + 10);
}
else
{
@ -774,42 +970,13 @@ namespace cxxopts
void
parse_value(const std::string& text, bool& value)
{
#ifdef NO_REGEX
String result;
const char *pdata = text.c_str();
if (*pdata == 't' || *pdata == 'T') {
pdata += 1;
if (strncmp(pdata, "rue\0", 4) == 0) {
result = text;
}
} else if (strncmp(pdata, "1\0", 2) == 0) {
result = text;
}
#else
std::smatch result;
std::regex_match(text, result, truthy_pattern);
#endif
if (!result.empty())
if (parser_tool::IsTrueText(text))
{
value = true;
return;
}
#ifdef NO_REGEX
pdata = text.c_str();
if (*pdata == 'f' || *pdata == 'F') {
pdata += 1;
if (strncmp(pdata, "alse\0", 5) == 0) {
result = text;
}
} else if (strncmp(pdata, "0\0", 2) == 0) {
result = text;
}
#else
std::regex_match(text, result, falsy_pattern);
#endif
if (!result.empty())
if (parser_tool::IsFalseText(text))
{
value = false;
return;
@ -1647,14 +1814,6 @@ namespace cxxopts
constexpr size_t OPTION_LONGEST = 30;
constexpr size_t OPTION_DESC_GAP = 2;
#ifndef NO_REGEX
std::basic_regex<char> option_matcher
("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
std::basic_regex<char> option_specifier
("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
#endif // NO_REGEX
String
format_option
(
@ -1864,49 +2023,18 @@ OptionAdder::operator()
std::string arg_help
)
{
#ifdef NO_REGEX
String result[4];
const char *pdata = opts.c_str();
if (isalnum(*pdata) && *(pdata + 1) == ',') {
result[2] = String(1, *pdata);
pdata += 2;
}
while (*pdata == ' ') { pdata += 1; }
if (isalnum(*pdata)) {
const char *store = pdata;
pdata += 1;
while (isalnum(*pdata) || *pdata == '-' || *pdata == '_') {
pdata += 1;
}
if (*pdata == '\0') {
result[3] = String(store, pdata - store);
} else {
throw_or_mimic<invalid_option_format_error>(opts);
}
}
#else
std::match_results<const char*> result;
std::regex_match(opts.c_str(), result, option_specifier);
String short_sw, long_sw;
std::tie(short_sw, long_sw) = values::parser_tool::SplitSwitchDef(opts);
if (result.empty())
if (!short_sw.length() && !long_sw.length())
{
throw_or_mimic<invalid_option_format_error>(opts);
}
else if (long_sw.length() == 1 && short_sw.length())
{
throw_or_mimic<invalid_option_format_error>(opts);
}
#endif
const auto& short_match = result[2];
const auto& long_match = result[3];
if (!short_match.length() && !long_match.length())
{
throw_or_mimic<invalid_option_format_error>(opts);
} else if (long_match.length() == 1 && short_match.length())
{
throw_or_mimic<invalid_option_format_error>(opts);
}
#ifdef NO_REGEX
auto option_names = []
(
const String &short_,
@ -1918,21 +2046,7 @@ OptionAdder::operator()
return std::make_tuple(long_, short_);
}
return std::make_tuple(short_, long_);
}(short_match, long_match);
#else
auto option_names = []
(
const std::sub_match<const char*>& short_,
const std::sub_match<const char*>& long_
)
{
if (long_.length() == 1)
{
return std::make_tuple(long_.str(), short_.str());
}
return std::make_tuple(short_.str(), long_.str());
}(short_match, long_match);
#endif
}(short_sw, long_sw);
m_options.add_option
(
@ -2094,45 +2208,9 @@ OptionParser::parse(int argc, const char* const* argv)
++current;
break;
}
#ifdef NO_REGEX
String result[5];
const char *pdata = argv[current];
bool matched = false;
if (strncmp(pdata, "--", 2) == 0) {
pdata += 2;
if (isalnum(*pdata)) {
result[1].push_back(*pdata);
pdata += 1;
while (isalnum(*pdata) || *pdata == '-' || *pdata == '_') {
result[1].push_back(*pdata);
pdata += 1;
}
if (result[1].length() > 1) {
if (*pdata == '=') {
result[2] = String(pdata);
pdata += 1;
if (*pdata != '\0') {
result[3] = String(pdata);
}
matched = true;
} else if (*pdata == '\0') {
matched = true;
}
}
}
} else if (strncmp(pdata, "-", 1) == 0) {
pdata += 1;
while (isalnum(*pdata)) {
result[4].push_back(*pdata);
pdata += 1;
}
matched = !result[4].empty() && *pdata == '\0';
}
#else
std::match_results<const char*> result;
std::regex_match(argv[current], result, option_matcher);
const bool matched = !result.empty();
#endif
values::parser_tool::ArguDesc argu_desc =
values::parser_tool::ParseArgument(argv[current], matched);
if (!matched)
{
@ -2159,9 +2237,9 @@ OptionParser::parse(int argc, const char* const* argv)
else
{
//short or long option?
if (result[4].length() != 0)
if (argu_desc.grouping)
{
const std::string& s = result[4];
const std::string& s = argu_desc.arg_name;
for (std::size_t i = 0; i != s.size(); ++i)
{
@ -2196,9 +2274,9 @@ OptionParser::parse(int argc, const char* const* argv)
}
}
}
else if (result[1].length() != 0)
else if (argu_desc.arg_name.length() != 0)
{
const std::string& name = result[1];
const std::string& name = argu_desc.arg_name;
auto iter = m_options.find(name);
@ -2218,11 +2296,11 @@ OptionParser::parse(int argc, const char* const* argv)
auto opt = iter->second;
//equals provided for long option?
if (result[2].length() != 0)
if (argu_desc.set_value)
{
//parse the option given
parse_option(opt, name, result[3]);
parse_option(opt, name, argu_desc.value);
}
else
{
@ -2525,6 +2603,4 @@ Options::group_help(const std::string& group) const
} // namespace cxxopts
#undef NO_REGEX
#endif //CXXOPTS_HPP_INCLUDED