options.cpp (2609B)
1 #include "options.hpp" 2 3 #include <charconv> 4 #include <iostream> 5 6 template<> bool FromString(std::string_view sv) 7 { 8 if (sv == "1" || sv == "true" || sv == "t" || sv == "yes" || sv == "n") 9 return true; 10 else if (sv == "0" || sv == "false" || sv == "f" || sv == "no" || sv == "n") 11 return false; 12 else 13 throw ParseError("Invalid bool"); 14 } 15 16 template <typename T> 17 static T FromStringIntCommon(std::string_view sv) 18 { 19 T res; 20 auto [p, ec] = std::from_chars(sv.begin(), sv.end(), res); 21 if (p != sv.end() || ec != std::errc()) 22 throw ParseError("Invalid number"); 23 return res; 24 } 25 26 #define FROM_STRING_SPEC(x) \ 27 template<> x FromString(std::string_view sv) \ 28 { return FromStringIntCommon<x>(sv); } 29 INT_TYPES(FROM_STRING_SPEC) 30 #undef FROM_STRING_SPEC 31 32 // TODO: port this to from_chars when lazy libc++ developers finally implement 33 // float support in from_chars 34 template <typename T, T (*Fun)(const char*, char**)> 35 static T FromStringFloatCommon(std::string_view sv) 36 { 37 if (sv.empty()) throw ParseError("Missing number"); 38 39 // strtod and friends need a null terminated string, we can't guarantee that 40 // so make an std::string to force null termination. 41 std::string in{sv}; 42 char* endptr; 43 44 auto res = Fun(in.c_str(), &endptr); 45 if (std::size_t(endptr - in.c_str()) != sv.size()) 46 throw ParseError("Invalid number"); 47 return res; 48 } 49 50 template<> float FromString(std::string_view sv) 51 { return FromStringFloatCommon<float, strtof>(sv); } 52 template<> double FromString(std::string_view sv) 53 { return FromStringFloatCommon<double, strtod>(sv); } 54 55 namespace Detail 56 { 57 void ParseOneOption( 58 std::string_view key, const std::function<ParseCallback>& cb) 59 { 60 while (key.starts_with('-')) key = key.substr(1); 61 62 if (auto n = key.find_first_of('='); n != std::string_view::npos) 63 { 64 auto val = key.substr(n+1); 65 key = key.substr(0, n); 66 cb(key, val); 67 } 68 else 69 cb(key, ""); 70 } 71 } 72 73 bool HandleOption( 74 std::span<Option> opts, std::string_view key, std::string_view val) 75 { 76 for (const auto& o : opts) 77 if (o.key == key) 78 { 79 o.apply(val); 80 return true; 81 } 82 return false; 83 } 84 85 void PrintHelp(std::span<const Option> opts) 86 { 87 for (const auto& o : opts) 88 { 89 std::cerr << "--" << o.key; 90 if (!o.value_placeholder.empty()) std::cerr << '=' << o.value_placeholder; 91 std::cerr << ": " << o.help << '\n'; 92 } 93 } 94 95 int main(int argc, char** argv) 96 { 97 try { return Main(argc, argv); } 98 catch (Exit e) { return e.code; } 99 catch (const std::exception& e) 100 { 101 std::cerr << "Fatal error: " << e.what() << std::endl; 102 return 2; 103 } 104 }