# HG changeset patch # User David Demelier # Date 1506760268 -7200 # Node ID fbd80bfcf58d1222733586f9ad07af48011878eb # Parent d7882b30b01a04619083722ff1dd4a8fd922b016 Irccd: import new options, closes #713 diff -r d7882b30b01a -r fbd80bfcf58d irccd/main.cpp --- a/irccd/main.cpp Fri Sep 29 17:04:03 2017 +0200 +++ b/irccd/main.cpp Sat Sep 30 10:31:08 2017 +0200 @@ -74,7 +74,7 @@ std::exit(1); } -void version(const option::Result& options) +void version(const option::result& options) { std::cout << IRCCD_VERSION << std::endl; @@ -126,13 +126,13 @@ ++ argv; } -option::Result parse(int& argc, char**& argv) +option::result parse(int& argc, char**& argv) { // Parse command line options. - option::Result result; + option::result result; try { - option::Options options{ + option::options options{ { "-c", true }, { "--config", true }, { "-f", false }, @@ -164,7 +164,7 @@ return result; } -config open(const option::Result& result) +config open(const option::result& result) { auto it = result.find("-c"); @@ -230,7 +230,7 @@ } } -void load_foreground(bool foreground, const option::Result& options) +void load_foreground(bool foreground, const option::result& options) { try { #if defined(HAVE_DAEMON) @@ -245,7 +245,7 @@ } } -void load(const config& config, const option::Result& options) +void load(const config& config, const option::result& options) { /* * Order matters, please be careful when changing this. @@ -289,7 +289,7 @@ { init(argc, argv); - option::Result options = parse(argc, argv); + option::result options = parse(argc, argv); instance = std::make_unique(); instance->commands().add(std::make_unique()); diff -r d7882b30b01a -r fbd80bfcf58d irccdctl/cli.cpp --- a/irccdctl/cli.cpp Fri Sep 29 17:04:03 2017 +0200 +++ b/irccdctl/cli.cpp Sat Sep 30 10:31:08 2017 +0200 @@ -352,9 +352,9 @@ namespace { -option::Result parse(std::vector &args) +option::result parse(std::vector &args) { - option::Options options{ + option::options options{ { "-c", true }, { "--command", true }, { "-n", true }, @@ -396,8 +396,8 @@ { std::vector copy(args); - option::Result result = parse(copy); - option::Result::const_iterator it; + option::result result = parse(copy); + option::result::const_iterator it; if (copy.size() < 2) throw std::invalid_argument("server-connect requires at least 2 arguments"); @@ -869,7 +869,7 @@ void RuleAddCli::exec(Irccdctl &irccdctl, const std::vector &args) { - static const option::Options options{ + static const option::options options{ { "-c", true }, { "--add-channel", true }, { "-e", true }, @@ -952,7 +952,7 @@ void RuleEditCli::exec(Irccdctl &irccdctl, const std::vector &args) { - static const option::Options options{ + static const option::options options{ { "-a", true }, { "--action", true }, { "-c", true }, diff -r d7882b30b01a -r fbd80bfcf58d irccdctl/main.cpp --- a/irccdctl/main.cpp Fri Sep 29 17:04:03 2017 +0200 +++ b/irccdctl/main.cpp Sat Sep 30 10:31:08 2017 +0200 @@ -298,9 +298,9 @@ * -h host or ip * -p port */ -void parseConnectIp(const option::Result &options) +void parseConnectIp(const option::result &options) { - option::Result::const_iterator it; + option::result::const_iterator it; // Host (-h or --host). std::string host; @@ -341,10 +341,10 @@ * * -P file */ -void parseConnectLocal(const option::Result &options) +void parseConnectLocal(const option::result &options) { #if !defined(IRCCD_SYSTEM_WINDOWS) - option::Result::const_iterator it; + option::result::const_iterator it; if ((it = options.find("-P")) == options.end() && (it = options.find("--path")) == options.end()) throw std::invalid_argument("missing path parameter (-P or --path)"); @@ -364,7 +364,7 @@ * * Generic parsing of command line option for connection. */ -void parseConnect(const option::Result &options) +void parseConnect(const option::result &options) { assert(options.count("-t") > 0 || options.count("--type") > 0); @@ -380,10 +380,10 @@ throw std::invalid_argument("invalid type given: " + it->second); } -option::Result parse(int &argc, char **&argv) +option::result parse(int &argc, char **&argv) { // 1. Parse command line options. - option::Options def{ + option::options def{ { "-c", true }, { "--config", true }, { "-h", true }, @@ -399,7 +399,7 @@ { "--verbose", false } }; - option::Result result; + option::result result; try { result = option::read(argc, argv, def); diff -r d7882b30b01a -r fbd80bfcf58d libcommon/irccd/options.cpp --- a/libcommon/irccd/options.cpp Fri Sep 29 17:04:03 2017 +0200 +++ b/libcommon/irccd/options.cpp Sat Sep 30 10:31:08 2017 +0200 @@ -1,7 +1,7 @@ /* * options.cpp -- parse Unix command line options * - * Copyright (c) 2015 David Demelier + * Copyright (c) 2015-2017 David Demelier * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,41 +26,40 @@ namespace { -using Iterator = std::vector::iterator; -using Args = std::vector; +using iterator = std::vector::iterator; +using args = std::vector; -inline bool isOption(const std::string &arg) noexcept +inline bool is_option(const std::string& arg) noexcept { return arg.size() >= 2 && arg[0] == '-'; } -inline bool isLongOption(const std::string &arg) noexcept +inline bool is_long_option(const std::string& arg) noexcept { - assert(isOption(arg)); + assert(is_option(arg)); return arg.size() >= 3 && arg[1] == '-'; } -inline bool isShortSimple(const std::string &arg) noexcept +inline bool is_short_simple(const std::string& arg) noexcept { - assert(isOption(arg)); - assert(!isLongOption(arg)); + assert(is_option(arg) && !is_long_option(arg)); return arg.size() == 2; } -void parseLongOption(Result &result, Args &args, Iterator &it, Iterator &end, const Options &definition) +void parse_long_option(result& result, args& args, iterator& it, iterator& end, const options& definition) { auto arg = *it++; auto opt = definition.find(arg); if (opt == definition.end()) - throw InvalidOption{arg}; + throw invalid_option(arg); // Need argument? if (opt->second) { - if (it == end || isOption(*it)) - throw MissingValue{arg}; + if (it == end || is_option(*it)) + throw missing_value(arg); result.insert(std::make_pair(arg, *it++)); it = args.erase(args.begin(), it); @@ -72,97 +71,106 @@ } } -void parseShortOption(Result &result, Args &args, Iterator &it, Iterator &end, const Options &definition) +void parse_short_option_simple(result& result, args& args, iterator& it, iterator &end, const options& definition) { - if (isShortSimple(*it)) { - /* - * Here two cases: - * - * -v (no option) - * -c value - */ - auto arg = *it++; - auto opt = definition.find(arg); + /* + * Here two cases: + * + * -v (no option) + * -c value + */ + auto arg = *it++; + auto opt = definition.find(arg); - if (opt == definition.end()) - throw InvalidOption{arg}; - - // Need argument? - if (opt->second) { - if (it == end || isOption(*it)) - throw MissingValue{arg}; + if (opt == definition.end()) + throw invalid_option(arg); - result.insert(std::make_pair(arg, *it++)); - it = args.erase(args.begin(), it); - end = args.end(); - } else { - result.insert(std::make_pair(arg, "")); - it = args.erase(args.begin()); - end = args.end(); - } + // Need argument? + if (opt->second) { + if (it == end || is_option(*it)) + throw missing_value(arg); + + result.insert(std::make_pair(arg, *it++)); + it = args.erase(args.begin(), it); + end = args.end(); } else { - /* - * Here multiple scenarios: - * - * 1. -abc (-a -b -c if all are simple boolean arguments) - * 2. -vc foo.conf (-v -c foo.conf if -c is argument dependant) - * 3. -vcfoo.conf (-v -c foo.conf also) - */ - auto value = it->substr(1); - auto len = value.length(); - int toremove = 1; - - for (decltype(len) i = 0; i < len; ++i) { - auto arg = std::string{'-'} + value[i]; - auto opt = definition.find(arg); - - if (opt == definition.end()) - throw InvalidOption{arg}; - - if (opt->second) { - if (i == (len - 1)) { - // End of string, get the next argument (see 2.). - if (++it == end || isOption(*it)) - throw MissingValue{arg}; - - result.insert(std::make_pair(arg, *it)); - toremove += 1; - } else { - result.insert(std::make_pair(arg, value.substr(i + 1))); - i = len; - } - } else - result.insert(std::make_pair(arg, "")); - } - - it = args.erase(args.begin(), args.begin() + toremove); + result.insert(std::make_pair(arg, "")); + it = args.erase(args.begin()); end = args.end(); } } +void parse_short_option_compressed(result& result, args& args, iterator& it, iterator &end, const options& definition) +{ + /* + * Here multiple scenarios: + * + * 1. -abc (-a -b -c if all are simple boolean arguments) + * 2. -vc foo.conf (-v -c foo.conf if -c is argument dependant) + * 3. -vcfoo.conf (-v -c foo.conf also) + */ + auto value = it->substr(1); + auto len = value.length(); + int toremove = 1; + + for (std::size_t i = 0; i < len; ++i) { + auto arg = std::string{'-'} + value[i]; + auto opt = definition.find(arg); + + if (opt == definition.end()) + throw invalid_option(arg); + + if (opt->second) { + if (i == (len - 1)) { + // End of string, get the next argument (see 2.). + if (++it == end || is_option(*it)) + throw missing_value(arg); + + result.insert(std::make_pair(arg, *it)); + toremove += 1; + } else { + result.insert(std::make_pair(arg, value.substr(i + 1))); + i = len; + } + } else + result.insert(std::make_pair(arg, "")); + } + + it = args.erase(args.begin(), args.begin() + toremove); + end = args.end(); +} + +void parse_short_option(result& result, args& args, iterator& it, iterator &end, const options& definition) +{ + if (is_short_simple(*it)) + parse_short_option_simple(result, args, it, end, definition); + else + parse_short_option_compressed(result, args, it, end, definition); +} + } // !namespace -Result read(std::vector &args, const Options &definition) +result read(std::vector& args, const options& definition) { - Result result; + result result; auto it = args.begin(); auto end = args.end(); while (it != end) { - if (!isOption(*it)) + if (!is_option(*it)) break; - if (isLongOption(*it)) - parseLongOption(result, args, it, end, definition); + if (is_long_option(*it)) + parse_long_option(result, args, it, end, definition); else - parseShortOption(result, args, it, end, definition); + parse_short_option(result, args, it, end, definition); } return result; } -Result read(int &argc, char **&argv, const Options &definition) +result read(int& argc, char**& argv, const options& definition) { std::vector args; diff -r d7882b30b01a -r fbd80bfcf58d libcommon/irccd/options.hpp --- a/libcommon/irccd/options.hpp Fri Sep 29 17:04:03 2017 +0200 +++ b/libcommon/irccd/options.hpp Sat Sep 30 10:31:08 2017 +0200 @@ -1,7 +1,7 @@ /* - * options.h -- parse Unix command line options + * options.hpp -- parse Unix command line options * - * Copyright (c) 2015 David Demelier + * Copyright (c) 2015-2017 David Demelier * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -30,8 +30,6 @@ #include #include -#include "sysconfig.hpp" - namespace irccd { /** @@ -42,25 +40,31 @@ /** * \brief This exception is thrown when an invalid option has been found. */ -class InvalidOption : public std::exception { +class invalid_option : public std::exception { private: - std::string message; + std::string message_; + std::string name_; public: /** - * The invalid option given. - */ - std::string argument; - - /** * Construct the exception. * * \param arg the argument missing */ - inline InvalidOption(std::string arg) - : argument(std::move(arg)) + inline invalid_option(std::string name) + : name_(std::move(name)) { - message = std::string("invalid option: ") + argument; + message_ = std::string("invalid option: ") + name_; + } + + /** + * Get the option name. + * + * \return the name + */ + inline const std::string& name() const noexcept + { + return name_; } /** @@ -68,40 +72,41 @@ * * \return the error message */ - const char *what() const noexcept override + const char* what() const noexcept override { - return message.c_str(); + return message_.c_str(); } }; /** - * \brief This exception is thrown when an option requires a value and no value has been given. + * \brief This exception is thrown when an option requires a value and no value + * has been given. */ -class MissingValue : public std::exception { +class missing_value : public std::exception { private: - std::string m_message; - std::string m_option; + std::string message_; + std::string name_; public: /** * Construct the exception. * - * \param option the option that requires a value + * \param name the option that requires a value */ - inline MissingValue(std::string option) - : m_option(std::move(option)) + inline missing_value(std::string name) + : name_(std::move(name)) { - m_message = std::string("missing argument for: ") + m_option; + message_ = std::string("missing argument for: ") + name_; } /** - * Get the options that requires a value. + * Get the option name. * - * \return the option name + * \return the name */ - inline const std::string &option() const noexcept + inline const std::string& name() const noexcept { - return m_option; + return name_; } /** @@ -109,21 +114,21 @@ * * \return the error message */ - const char *what() const noexcept override + const char* what() const noexcept override { - return m_message.c_str(); + return message_.c_str(); } }; /** * Packed multimap of options. */ -using Result = std::multimap; +using result = std::multimap; /** * Define the allowed options. */ -using Options = std::map; +using options = std::map; /** * Extract the command line options and return a result. @@ -131,10 +136,10 @@ * \param args the arguments * \param definition * \warning the arguments vector is modified in place to remove parsed options - * \throw MissingValue - * \throw InvalidOption + * \throw missing_value + * \throw invalid_option */ -IRCCD_EXPORT Result read(std::vector &args, const Options &definition); +result read(std::vector& args, const options& definition); /** * Overloaded function for usage with main() arguments. @@ -144,13 +149,13 @@ * \param definition * \note don't forget to remove the first argv[0] argument * \warning the argc and argv are modified in place to remove parsed options - * \throw MissingValue - * \throw InvalidOption + * \throw missing_value + * \throw invalid_option */ -IRCCD_EXPORT Result read(int &argc, char **&argv, const Options &definition); +result read(int& argc, char**& argv, const options& definition); } // !option } // !irccd -#endif // !IRCCD_OPTIONS_HPP +#endif // !OPTIONS_HPP