#include "arg_parser.h" #include #include #include ArgParser::ArgParser() {} ArgParser::~ArgParser() {} ArgParser::Option* ArgParser::FindOptionByShortName(const std::string& short_name) { ArgParser::Option* p_option = nullptr; auto it = std::find_if(std::begin(m_options), std::end(m_options), [short_name](const ArgParser::Option& elem) -> bool { return elem.short_name == short_name; }); if (it != std::end(m_options)) { p_option = &(*it); } return p_option; } const ArgParser::Option* ArgParser::FindOptionByShortName(const std::string& short_name) const { const ArgParser::Option* p_option = nullptr; auto it = std::find_if(std::begin(m_options), std::end(m_options), [short_name](const ArgParser::Option& elem) -> bool { return elem.short_name == short_name; }); if (it != std::end(m_options)) { p_option = &(*it); } return p_option; } ArgParser::Option* ArgParser::FindOptionByLongName(const std::string& long_name) { ArgParser::Option* p_option = nullptr; auto it = std::find_if(std::begin(m_options), std::end(m_options), [long_name](const ArgParser::Option& elem) -> bool { return elem.long_name == long_name; }); if (it != std::end(m_options)) { p_option = &(*it); } return p_option; } const ArgParser::Option* ArgParser::FindOptionByLongName(const std::string& long_name) const { const ArgParser::Option* p_option = nullptr; auto it = std::find_if(std::begin(m_options), std::end(m_options), [long_name](const ArgParser::Option& elem) -> bool { return elem.long_name == long_name; }); if (it != std::end(m_options)) { p_option = &(*it); } return p_option; } bool ArgParser::AddFlag(const std::string& short_name, const std::string& long_name, const std::string& desc) { Option option = {}; option.short_name = short_name; option.long_name = long_name; option.type = OPTION_TYPE_FLAG; option.desc = desc; auto p_short = FindOptionByShortName(short_name); auto p_long = FindOptionByLongName(long_name); if ((p_short != nullptr) || (p_long != nullptr)) { return false; } m_options.push_back(option); return true; } bool ArgParser::AddOptionString(const std::string& short_name, const std::string& long_name, const std::string& desc, const std::string& default_value) { Option option = {}; option.short_name = short_name; option.long_name = long_name; option.type = OPTION_TYPE_STRING; option.desc = desc; option.default_value.str = default_value; auto p_short = FindOptionByShortName(short_name); auto p_long = FindOptionByLongName(long_name); if ((p_short != nullptr) || (p_long != nullptr)) { return false; } m_options.push_back(option); return true; } bool ArgParser::AddOptionInt(const std::string& short_name, const std::string& long_name, const std::string& desc, int default_value) { Option option = {}; option.short_name = short_name; option.long_name = long_name; option.type = OPTION_TYPE_INT; option.desc = desc; option.default_value.i32 = default_value; auto p_short = FindOptionByShortName(short_name); auto p_long = FindOptionByLongName(long_name); if ((p_short != nullptr) || (p_long != nullptr)) { return false; } m_options.push_back(option); return true; } bool ArgParser::AddOptionFloat(const std::string& short_name, const std::string& long_name, const std::string& desc, float default_value) { Option option = {}; option.short_name = short_name; option.long_name = long_name; option.type = OPTION_TYPE_FLOAT; option.desc = desc; option.default_value.f32 = default_value; auto p_short = FindOptionByShortName(short_name); auto p_long = FindOptionByLongName(long_name); if ((p_short != nullptr) || (p_long != nullptr)) { return false; } m_options.push_back(option); return true; } bool ArgParser::Parse(int argc, char** argv, std::ostream& os) { for (auto& opt : m_options) { opt.value = opt.default_value; opt.parsed = false; } int i = 1; while (i < argc) { std::string s = argv[i]; if (s[0] == '-') { ArgParser::Option* p_option = nullptr; if ((s.length() >= 2) && ((s[0] == '-') && (s[1] == '-'))) { std::string long_name = s.substr(2); p_option = FindOptionByLongName(long_name); } else { std::string short_name = s.substr(1); p_option = FindOptionByShortName(short_name); } if (p_option == nullptr) { os << "ERROR: invalid argument " << s << std::endl; return false; } switch (p_option->type) { case OPTION_TYPE_FLAG: { p_option->parsed = true; i += 1; } break; case OPTION_TYPE_STRING: { if ((i + 1) >= argc) { os << "ERROR: missing option data for " << s << std::endl; return false; } s = argv[i + 1]; p_option->value.str = s; p_option->parsed = true; i += 2; } break; case OPTION_TYPE_INT: { if ((i + 1) >= argc) { os << "ERROR: missing option data for " << s << std::endl; return false; } s = argv[i + 1]; p_option->value.i32 = atoi(s.c_str()); p_option->parsed = true; i += 2; } break; case OPTION_TYPE_FLOAT: { if ((i + 1) >= argc) { os << "ERROR: missing option data for " << s << std::endl; return false; } s = argv[i + 1]; p_option->value.f32 = static_cast(atof(s.c_str())); p_option->parsed = true; i += 2; } break; case OPTION_TYPE_UNDEFINED: { } break; } } else { m_args.push_back(s); i += 1; } } return true; } size_t ArgParser::GetArgCount() const { return m_args.size(); } bool ArgParser::GetArg(size_t i, std::string* p_value) const { if ((GetArgCount() == 0) && (i >= GetArgCount())) { return false; } if (p_value != nullptr) { *p_value = m_args[i]; } return true; } const std::vector& ArgParser::GetArgs() const { return m_args; } bool ArgParser::GetFlag(const std::string& short_name, const std::string& long_name) const { auto p_short = FindOptionByShortName(short_name); auto p_long = FindOptionByLongName(long_name); const ArgParser::Option* p_option = nullptr; if (p_short != nullptr) { p_option = p_short; } if ((p_option == nullptr) && (p_long != nullptr)) { p_option = p_short; } if (p_option == nullptr) { return false; } if (p_option->type != OPTION_TYPE_FLAG) { return false; } return p_option->parsed; } bool ArgParser::GetString(const std::string& short_name, const std::string& long_name, std::string* p_value) const { auto p_short = FindOptionByShortName(short_name); auto p_long = FindOptionByLongName(long_name); const ArgParser::Option* p_option = nullptr; if (p_short != nullptr) { p_option = p_short; } if ((p_option == nullptr) && (p_long != nullptr)) { p_option = p_short; } if (p_option == nullptr) { return false; } if (!p_option->parsed || (p_option->type != OPTION_TYPE_STRING)) { return false; } if (p_value != nullptr) { *p_value = p_option->value.str; } return true; } bool ArgParser::GetInt(const std::string& short_name, const std::string& long_name, int* p_value) const { auto p_short = FindOptionByShortName(short_name); auto p_long = FindOptionByLongName(long_name); const ArgParser::Option* p_option = nullptr; if (p_short != nullptr) { p_option = p_short; } if ((p_option == nullptr) && (p_long != nullptr)) { p_option = p_short; } if (p_option == nullptr) { return false; } if (!p_option->parsed || (p_option->type != OPTION_TYPE_INT)) { return false; } if (p_value != nullptr) { *p_value = p_option->value.i32; } return true; } bool ArgParser::GetFloat(const std::string& short_name, const std::string& long_name, float* p_value) const { auto p_short = FindOptionByShortName(short_name); auto p_long = FindOptionByLongName(long_name); const ArgParser::Option* p_option = nullptr; if (p_short != nullptr) { p_option = p_short; } if ((p_option == nullptr) && (p_long != nullptr)) { p_option = p_short; } if (p_option == nullptr) { return false; } if (!p_option->parsed || (p_option->type != OPTION_TYPE_FLOAT)) { return false; } if (p_value != nullptr) { *p_value = p_option->value.f32; } return true; } void ArgParser::PrintHelp(std::ostream& os) { (void)os; /* if (m_options.empty()) { return; } struct TextLine { std::string option; std::string desc; }; std::vector text_lines; size_t max_width = 0; for (auto& it : m_options) { std::stringstream ss; ss << "--" << it.first; switch (it.second.type) { default: break; case OPTION_TYPE_STRING : ss << " " << "[s]"; break; case OPTION_TYPE_INT : ss << " " << "[i]"; break; case OPTION_TYPE_FLOAT : ss << " " << "[f]"; break; } std::string option = ss.str(); max_width = std::max(max_width, option.size()); TextLine tl; tl.option = option; tl.desc = it.second.desc; text_lines.push_back(tl); } max_width += 2; os << "\n"; os << "Options:" << "\n"; for (auto& tl : text_lines) { os << " "; os << std::left << std::setw(max_width) << tl.option; os << tl.desc; os << "\n"; } */ }