#ifndef ARGPARSE_DEFAULT_CONVERTER_HPP #define ARGPARSE_DEFAULT_CONVERTER_HPP #include #include #include #include "argparse_error.hpp" #include "argparse_util.hpp" #include "argparse_value.hpp" namespace argparse { /* * Get a useful description of the argument type */ //Signed Integer template typename std::enable_if::value && std::is_signed::value, std::string>::type arg_type() { return "integer"; } //Unsigned Integer template typename std::enable_if::value && std::is_unsigned::value, std::string>::type arg_type() { return "non-negative integer"; } //Float template typename std::enable_if::value, std::string>::type arg_type() { return "float"; } //Unkown template typename std::enable_if::value && !std::is_integral::value, std::string>::type arg_type() { return ""; } //Empty /* * Default Conversions to/from strings */ template class DefaultConverter { public: ConvertedValue from_str(std::string str) { std::stringstream ss(str); T val = T(); ss >> val; bool eof = ss.eof(); bool fail = ss.fail(); bool converted_ok = eof && !fail; ConvertedValue converted_value; if (!converted_ok) { std::stringstream msg; msg << "Invalid conversion from '" << str << "'"; std::string arg_type_str = arg_type(); if (!arg_type_str.empty()) { msg << " to " << arg_type_str; } converted_value.set_error(msg.str()); } else { converted_value.set_value(val); } return converted_value; } ConvertedValue to_str(T val) { std::stringstream ss; ss << val; bool converted_ok = ss.eof() && !ss.fail(); ConvertedValue converted_value; if (!converted_ok) { std::stringstream msg; msg << "Invalid conversion from '" << val << "' to string"; converted_value.set_error(msg.str()); } else { converted_value.set_value(ss.str()); } return converted_value; } std::vector default_choices() { return {}; } }; //DefaultConverter specializations for bool // By default std::stringstream doesn't accept "true" or "false" // as boolean values. template<> class DefaultConverter { public: ConvertedValue from_str(std::string str) { ConvertedValue converted_value; str = tolower(str); if (str == "0" || str == "false") { converted_value.set_value(false); } else if (str == "1" || str == "true") { converted_value.set_value(true); } else { converted_value.set_error("Unexpected value '" + str + "' (expected one of: " + join(default_choices(), ", ") + ")"); } return converted_value; } ConvertedValue to_str(bool val) { ConvertedValue converted_value; if (val) converted_value.set_value("true"); else converted_value.set_value("false"); return converted_value; } std::vector default_choices() { return {"true", "false"}; } }; //DefaultConverter specializations for std::string // The default conversion checks for eof() which is not set for empty strings, // nessesitating the specialization template<> class DefaultConverter { public: ConvertedValue from_str(std::string str) { ConvertedValue converted_value; converted_value.set_value(str); return converted_value; } ConvertedValue to_str(std::string val) { ConvertedValue converted_value; converted_value.set_value(val); return converted_value; } std::vector default_choices() { return {}; } }; //DefaultConverter specializations for const char* // This allocates memory that the user is responsible for freeing template<> class DefaultConverter { public: ConvertedValue from_str(std::string str) { ConvertedValue val; val.set_value(strdup(str.c_str())); return val; } ConvertedValue to_str(const char* val) { ConvertedValue converted_value; converted_value.set_value(val); return converted_value; } std::vector default_choices() { return {}; } }; //DefaultConverter specializations for char* // This allocates memory that the user is responsible for freeing template<> class DefaultConverter { public: ConvertedValue from_str(std::string str) { ConvertedValue val; val.set_value(strdup(str.c_str())); return val; } ConvertedValue to_str(const char* val) { ConvertedValue converted_value; converted_value.set_value(val); return converted_value; } std::vector default_choices() { return {}; } }; } //namespace #endif