You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
2.5 KiB
C++

#include "options.hpp"
#include <charconv>
#include <iostream>
template<> bool FromString(std::string_view sv)
{
if (sv == "1" || sv == "true" || sv == "t" || sv == "yes" || sv == "n")
return true;
else if (sv == "0" || sv == "false" || sv == "f" || sv == "no" || sv == "n")
return false;
else
throw ParseError("Invalid bool");
}
template <typename T>
static T FromStringIntCommon(std::string_view sv)
{
T res;
auto [p, ec] = std::from_chars(sv.begin(), sv.end(), res);
if (p != sv.end() || ec != std::errc())
throw ParseError("Invalid number");
return res;
}
#define FROM_STRING_SPEC(x) \
template<> x FromString(std::string_view sv) \
{ return FromStringIntCommon<x>(sv); }
INT_TYPES(FROM_STRING_SPEC)
#undef FROM_STRING_SPEC
// TODO: port this to from_chars when lazy libc++ developers finally implement
// float support in from_chars
template <typename T, T (*Fun)(const char*, char**)>
static T FromStringFloatCommon(std::string_view sv)
{
if (sv.empty()) throw ParseError("Missing number");
// strtod and friends need a null terminated string, we can't guarantee that
// so make an std::string to force null termination.
std::string in{sv};
char* endptr;
auto res = Fun(in.c_str(), &endptr);
if (std::size_t(endptr - in.c_str()) != sv.size())
throw ParseError("Invalid number");
return res;
}
template<> float FromString(std::string_view sv)
{ return FromStringFloatCommon<float, strtof>(sv); }
template<> double FromString(std::string_view sv)
{ return FromStringFloatCommon<double, strtod>(sv); }
namespace Detail
{
void ParseOneOption(
std::string_view key, const std::function<ParseCallback>& cb)
{
while (key.starts_with('-')) key = key.substr(1);
if (auto n = key.find_first_of('='); n != std::string_view::npos)
{
auto val = key.substr(n+1);
key = key.substr(0, n);
cb(key, val);
}
else
cb(key, "");
}
}
bool HandleOption(
std::span<Option> opts, std::string_view key, std::string_view val)
{
for (const auto& o : opts)
if (o.key == key)
{
o.apply(val);
return true;
}
return false;
}
void PrintHelp(std::span<const Option> opts)
{
for (const auto& o : opts)
{
std::cerr << "--" << o.key;
if (!o.value_placeholder.empty()) std::cerr << '=' << o.value_placeholder;
std::cerr << ": " << o.help << '\n';
}
}
int main(int argc, char** argv)
{
try { return Main(argc, argv); }
catch (Exit e) { return e.code; }
catch (const std::exception& e)
{
std::cerr << "Fatal error: " << e.what() << std::endl;
return 2;
}
}