flags-cpp/flags.cpp

166 lines
4.2 KiB
C++
Raw Normal View History

2023-11-30 20:36:11 +00:00
#include "flags.h"
2023-12-01 14:22:58 +00:00
2023-12-01 02:32:03 +00:00
#include <iostream>
2023-12-01 14:22:58 +00:00
#include <sstream>
2023-11-30 20:36:11 +00:00
namespace Flags {
2023-12-01 14:22:58 +00:00
std::vector<std::string> split(const std::string& input, const char separator) {
2023-11-30 20:36:11 +00:00
std::vector<std::string> result;
std::istringstream stream(input);
std::string part;
while (std::getline(stream, part, separator))
result.push_back(part);
return result;
}
2023-12-01 14:22:58 +00:00
bool starts_with(const std::string& input, const std::string& start) {
return (input.size() >= start.size() && input.substr(0, start.size()) == start);
2023-12-01 02:32:03 +00:00
}
PARSER(StringFlag, std::string, {
set_found(true);
set_parsed(true);
value = arg;
})
PARSER(IntFlag, int, {
set_found(true);
try {
value = std::stoi(arg);
set_parsed(true);
2023-12-01 14:22:58 +00:00
} catch (std::exception&) {
2023-12-01 02:32:03 +00:00
}
})
PARSER(LongIntFlag, long int, {
set_found(true);
try {
value = std::stol(arg);
set_parsed(true);
2023-12-01 14:22:58 +00:00
} catch (std::exception&) {
2023-12-01 02:32:03 +00:00
}
})
PARSER(LongLongIntFlag, long long int, {
set_found(true);
try {
value = std::stoll(arg);
set_parsed(true);
2023-12-01 14:22:58 +00:00
} catch (std::exception&) {
2023-12-01 02:32:03 +00:00
}
})
PARSER(UnsignedLongIntFlag, unsigned long int, {
set_found(true);
try {
value = std::stoul(arg);
set_parsed(true);
2023-12-01 14:22:58 +00:00
} catch (std::exception&) {
2023-12-01 02:32:03 +00:00
}
})
PARSER(UnsignedLongLongIntFlag, unsigned long long int, {
set_found(true);
try {
value = std::stoull(arg);
set_parsed(true);
2023-12-01 14:22:58 +00:00
} catch (std::exception&) {
2023-12-01 02:32:03 +00:00
}
})
PARSER(FloatFlag, float, {
set_found(true);
try {
value = std::stof(arg);
set_parsed(true);
2023-12-01 14:22:58 +00:00
} catch (std::exception&) {
2023-12-01 02:32:03 +00:00
}
})
PARSER(DoubleFlag, double, {
set_found(true);
try {
value = stod(arg);
set_parsed(true);
2023-12-01 14:22:58 +00:00
} catch (std::exception&) {
2023-12-01 02:32:03 +00:00
}
})
PARSER(LongDoubleFlag, long double, {
set_found(true);
try {
value = stold(arg);
set_parsed(true);
2023-12-01 14:22:58 +00:00
} catch (std::exception&) {
2023-12-01 02:32:03 +00:00
}
})
PARSER(BoolFlag, bool, {
std::string copy(arg);
2023-12-01 14:22:58 +00:00
std::transform(copy.begin(), copy.end(), copy.begin(), [](const char c) { return std::tolower(c); });
2023-12-01 02:32:03 +00:00
if (copy == "false")
value = false;
else
value = true;
})
2023-12-01 14:22:58 +00:00
Parser::Parser(const std::string& prefix, const std::string& help_text) : prefix(prefix), help_text(help_text) {
2023-12-01 02:32:03 +00:00
set_parser<std::string>(flag_constructor_t(StringFlag::make));
set_parser<int>(flag_constructor_t(IntFlag::make));
set_parser<long int>(flag_constructor_t(LongIntFlag::make));
set_parser<long long int>(flag_constructor_t(LongLongIntFlag::make));
set_parser<unsigned long int>(flag_constructor_t(UnsignedLongIntFlag::make));
2023-12-01 14:22:58 +00:00
set_parser<unsigned long long int>(flag_constructor_t(UnsignedLongLongIntFlag::make));
2023-12-01 02:32:03 +00:00
set_parser<float>(flag_constructor_t(FloatFlag::make));
set_parser<double>(flag_constructor_t(DoubleFlag::make));
set_parser<long double>(flag_constructor_t(LongDoubleFlag::make));
set_parser<bool>(flag_constructor_t(BoolFlag::make));
2023-11-30 20:36:11 +00:00
}
2023-12-01 14:22:58 +00:00
bool Parser::parse(int argc, char** argv) {
2023-11-30 20:36:11 +00:00
// put each argument into a std::string
std::vector<std::string> args;
for (int i = 0; i < argc; i++) {
std::string arg(argv[i]);
2023-12-01 02:32:03 +00:00
if (starts_with(arg, prefix) && arg.size() > prefix.size()) {
2023-11-30 20:36:11 +00:00
std::vector<std::string> parts = split(arg, '=');
args.insert(args.end(), parts.begin(), parts.end());
} else {
args.push_back(arg);
}
}
// search for flags
for (size_t i = 1; i < args.size() - 1; i++) {
2023-12-01 14:22:58 +00:00
const std::string& arg = args[i];
2023-12-01 02:32:03 +00:00
if (starts_with(arg, prefix) && arg.size() > prefix.size()) {
flags[arg.substr(prefix.size())]->parse(args[i + 1]);
2023-11-30 20:36:11 +00:00
}
}
// check for the last argument
2023-12-01 14:22:58 +00:00
if (starts_with(args[args.size() - 1], prefix) && args[args.size() - 1].size() > prefix.size()) {
2023-12-01 02:32:03 +00:00
flags[args[args.size() - 1].substr(prefix.size())]->parse("");
2023-11-30 20:36:11 +00:00
}
return get_found() == flags.size();
}
2023-12-01 02:32:03 +00:00
unsigned Parser::get_parsed() const {
2023-12-01 14:22:58 +00:00
return std::count_if(flags.begin(), flags.end(), [](std::pair<std::string, Flag*> f) { return f.second->get_parsed(); });
2023-11-30 20:36:11 +00:00
}
2023-12-01 02:32:03 +00:00
unsigned Parser::get_found() const {
2023-12-01 14:22:58 +00:00
return std::count_if(flags.begin(), flags.end(), [](std::pair<std::string, Flag*> f) { return f.second->get_found(); });
2023-11-30 20:36:11 +00:00
}
void Parser::help() const {
std::cout << help_text << std::endl;
for (auto f : flags) {
2023-12-01 14:22:58 +00:00
std::cout << '\t' << prefix << f.first << ": " << f.second->get_description() << std::endl;
2023-11-30 20:36:11 +00:00
}
}
} // namespace Flags