Mercurial > code
diff C++/OptionParser.cpp @ 236:ff2db0ed78f1
* Import GoogleTest
* Start testing of OptionParser
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 04 Jul 2014 22:16:04 +0200 |
parents | 96ff112d05cf |
children | 99e83685d4da |
line wrap: on
line diff
--- a/C++/OptionParser.cpp Thu Jun 26 16:49:00 2014 +0200 +++ b/C++/OptionParser.cpp Fri Jul 04 22:16:04 2014 +0200 @@ -28,8 +28,8 @@ Option::Option(const std::string &name, const std::string &help, Type type, int flags) : m_name(name) , m_help(help) + , m_flags(flags) , m_type(type) - , m_flags(flags) { } @@ -38,6 +38,11 @@ return m_name; } +const std::string &Option::token() const +{ + return m_token; +} + const std::string &Option::help() const { return m_help; @@ -137,35 +142,92 @@ * OptionParser class * -------------------------------------------------------- */ +OptionParser::Args OptionParser::unpack(const Args &args) const +{ + if (m_style != Getopt) + return args; + + Args ret; + + for (const auto &s : args) { + auto length = s.length(); + + if (length < 2 || s[0] != '-' || s[1] == '-') { + ret.push_back(s); + continue; + } + + for (int i = 1; i < (int)length; ++i) { + ret.push_back(std::string("-") + std::string(&s[i], 1)); + } + } + + return ret; +} + +OptionParser::OptionParser(Style style) + : m_style(style) +{ +} + void OptionParser::add(Option &&option) { - const auto &name = option.name(); + const auto &length = option.m_name.size(); + + if (length > m_maxlength) + m_maxlength = length; - if (name.length() > m_maxlength) - m_maxlength = name.length(); + /* + * If style is Getopt, we should use a double dash as the long option + * like --color and a single for short options like -v + */ + if (m_style == Getopt) { + if (length > 1) + option.m_token = "--" + option.m_name; + else + option.m_token = "-" + option.m_name; + } else + option.m_token = "/" + option.m_name; - m_options.emplace(std::make_pair(name, std::move(option))); + m_options.emplace(std::make_pair(option.m_token, std::move(option))); } void OptionParser::add(const Option &option) { - add(const_cast<Option &>(option)); + add(Option(option)); } -OptionResult OptionParser::parse(int argc, char **argv, int flags) +OptionResult OptionParser::parse(int argc, const char * const *argv, int flags) +{ + Args args; + + for (int i = 0; i < argc; ++i) + args.push_back(argv[i]); + + return parse(args, flags); +} + +OptionResult OptionParser::parse(const Args &argslist, int flags) { OptionResult result; int i; + auto args = unpack(argslist); + auto length = args.size(); - for (i = 0; i < argc; ++i) { + for (i = 0; i < (int)length; ++i) { /* Not a valid option at all? */ - if (m_options.count(argv[i]) == 0) { - log(argv[i], std::string(argv[i]) + " is not a valid option"); - + if (m_options.count(args[i]) == 0) { + /* When breaking is enabled we should not emit a warning */ if (flags & Strict) { - usage(); + if (!(flags & Silent)) { + log(args[i], args[i] + " is not a valid option"); + usage(); + } + break; - } else + } else if (flags & BreakNonOption) + break; + else continue; } @@ -173,14 +235,14 @@ * At this step, we have an option name valid, check if it requires * an argument or not. */ - const auto &option = m_options.at(argv[i]); + const auto &option = m_options.at(args[i]); const auto &name = option.name(); auto type = option.type(); /* * Already present and must appears only once? */ - if (option.flags() & Option::Single && m_placed.count(name) > 0) { + if ((option.flags() & Option::Single) && m_placed.count(name) > 0) { if (!(flags & Silent)) { log(name, "option " + name + " must appear only once"); @@ -198,10 +260,10 @@ if (type == Option::Type::Switch) result.m_values.push_back(OptionValue(name)); else { - if (i + 1 >= argc) + if (i + 1 >= (int)length) result.m_values.push_back(OptionValue(name, "")); else { - result.m_values.push_back(OptionValue(name, argv[i + 1])); + result.m_values.push_back(OptionValue(name, args[i + 1])); ++ i; } } @@ -212,14 +274,17 @@ result.m_total = i; return result; + } void OptionParser::usage() { std::cout << "options available: " << std::endl; - for (const auto &option : m_options) - std::cout << " " << std::setw(m_maxlength) << option.second.name() << "\t" << option.second.help() << std::endl; + for (const auto &option : m_options) { + std::cout << " " << std::setw(m_maxlength) << option.second.name(); + std::cout << "\t" << option.second.help() << std::endl; + } } void OptionParser::log(const std::string &, const std::string &error)