changeset 643:29e6ef5cd606

options: use Boost.ProgramOptions instead
author David Demelier <markand@malikania.fr>
date Wed, 01 Aug 2018 13:58:03 +0200
parents 18aa7181e0c3
children 0a947aec477c
files cpp/CMakeLists.txt cpp/options/CMakeLists.txt cpp/options/options.cpp cpp/options/options.hpp cpp/options/test/main.cpp
diffstat 5 files changed, 0 insertions(+), 638 deletions(-) [+]
line wrap: on
line diff
--- a/cpp/CMakeLists.txt	Wed Aug 01 13:56:54 2018 +0200
+++ b/cpp/CMakeLists.txt	Wed Aug 01 13:58:03 2018 +0200
@@ -20,5 +20,4 @@
 add_subdirectory(is_number)
 add_subdirectory(join)
 add_subdirectory(json_util)
-add_subdirectory(options)
 add_subdirectory(to_int)
--- a/cpp/options/CMakeLists.txt	Wed Aug 01 13:56:54 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-#
-# CMakeLists.txt -- options module
-#
-# Copyright (c) 2015-2018 David Demelier <markand@malikania.fr>
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-
-project(options)
-
-code_define_module(
-    NAME options
-    SOURCES
-        ${options_SOURCE_DIR}/options.cpp
-        ${options_SOURCE_DIR}/options.hpp
-)
--- a/cpp/options/options.cpp	Wed Aug 01 13:56:54 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,187 +0,0 @@
-/*
- * options.cpp -- parse Unix command line options
- *
- * Copyright (c) 2015-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <cassert>
-
-#include "options.hpp"
-
-namespace option {
-
-namespace {
-
-using iterator = std::vector<std::string>::iterator;
-using args = std::vector<std::string>;
-
-inline bool is_option(const std::string& arg) noexcept
-{
-    return arg.size() >= 2 && arg[0] == '-';
-}
-
-inline bool is_long_option(const std::string& arg) noexcept
-{
-    assert(is_option(arg));
-
-    return arg.size() >= 3 && arg[1] == '-';
-}
-
-inline bool is_short_simple(const std::string& arg) noexcept
-{
-    assert(is_option(arg) && !is_long_option(arg));
-
-    return arg.size() == 2;
-}
-
-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 invalid_option(arg);
-
-    // 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 {
-        result.insert(std::make_pair(arg, ""));
-        it = args.erase(args.begin());
-        end = args.end();
-    }
-}
-
-void parse_short_option_simple(result& result, args& args, iterator& it, iterator &end, const options& definition)
-{
-    /*
-     * Here two cases:
-     *
-     * -v (no option)
-     * -c value
-     */
-    auto arg = *it++;
-    auto opt = definition.find(arg);
-
-    if (opt == definition.end())
-        throw invalid_option(arg);
-
-    // 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 {
-        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<std::string>& args, const options& definition)
-{
-    result result;
-
-    auto it = args.begin();
-    auto end = args.end();
-
-    while (it != end) {
-        if (!is_option(*it))
-            break;
-
-        if (is_long_option(*it))
-            parse_long_option(result, args, it, end, definition);
-        else
-            parse_short_option(result, args, it, end, definition);
-    }
-
-    return result;
-}
-
-result read(int& argc, char**& argv, const options& definition)
-{
-    std::vector<std::string> args;
-
-    for (int i = 0; i < argc; ++i)
-        args.push_back(argv[i]);
-
-    auto before = args.size();
-    auto result = read(args, definition);
-
-    argc -= before - args.size();
-    argv += before - args.size();
-
-    return result;
-}
-
-} // !option
--- a/cpp/options/options.hpp	Wed Aug 01 13:56:54 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-/*
- * options.hpp -- parse Unix command line options
- *
- * Copyright (c) 2015-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef OPTIONS_HPP
-#define OPTIONS_HPP
-
-/**
- * \file options.hpp
- * \brief Basic Unix options parser.
- */
-
-/**
- * \page options Options parser.
- *
- * ## Export macros
- *
- * You must define `OPTIONS_DLL` globally and `OPTIONS_BUILDING_DLL` when
- * compiling the library if you want a DLL, alternatively you can provide your
- * own `OPTIONS_EXPORT` macro instead.
- */
-
-/**
- * \cond OPTIONS_HIDDEN_SYMBOLS
- */
-
-#if !defined(OPTIONS_EXPORT)
-#   if defined(OPTIONS_DLL)
-#       if defined(_WIN32)
-#           if defined(OPTIONS_BUILDING_DLL)
-#               define OPTIONS_EXPORT __declspec(dllexport)
-#           else
-#               define OPTIONS_EXPORT __declspec(dllimport)
-#           endif
-#       else
-#           define OPTIONS_EXPORT
-#       endif
-#   else
-#       define OPTIONS_EXPORT
-#   endif
-#endif
-
-/**
- * \endcond
- */
-
-#include <exception>
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-
-/**
- * Namespace for options parsing.
- */
-namespace option {
-
-/**
- * \brief This exception is thrown when an invalid option has been found.
- */
-class invalid_option : public std::exception {
-private:
-    std::string message_;
-    std::string name_;
-
-public:
-    /**
-     * Construct the exception.
-     *
-     * \param name the argument missing
-     */
-    inline invalid_option(std::string name)
-        : name_(std::move(name))
-    {
-        message_ = std::string("invalid option: ") + name_;
-    }
-
-    /**
-     * Get the option name.
-     *
-     * \return the name
-     */
-    inline const std::string& name() const noexcept
-    {
-        return name_;
-    }
-
-    /**
-     * Get the error message.
-     *
-     * \return the error message
-     */
-    const char* what() const noexcept override
-    {
-        return message_.c_str();
-    }
-};
-
-/**
- * \brief This exception is thrown when an option requires a value and no value
- * has been given.
- */
-class missing_value : public std::exception {
-private:
-    std::string message_;
-    std::string name_;
-
-public:
-    /**
-     * Construct the exception.
-     *
-     * \param name the option that requires a value
-     */
-    inline missing_value(std::string name)
-        : name_(std::move(name))
-    {
-        message_ = std::string("missing argument for: ") + name_;
-    }
-
-    /**
-     * Get the option name.
-     *
-     * \return the name
-     */
-    inline const std::string& name() const noexcept
-    {
-        return name_;
-    }
-
-    /**
-     * Get the error message.
-     *
-     * \return the error message
-     */
-    const char* what() const noexcept override
-    {
-        return message_.c_str();
-    }
-};
-
-/**
- * Packed multimap of options.
- */
-using result = std::multimap<std::string, std::string>;
-
-/**
- * Define the allowed options.
- */
-using options = std::map<std::string, bool>;
-
-/**
- * Extract the command line options and return a result.
- *
- * \param args the arguments
- * \param definition
- * \warning the arguments vector is modified in place to remove parsed options
- * \throw missing_value
- * \throw invalid_option
- */
-OPTIONS_EXPORT result read(std::vector<std::string>& args, const options& definition);
-
-/**
- * Overloaded function for usage with main() arguments.
- *
- * \param argc the number of arguments
- * \param argv the argument vector
- * \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 missing_value
- * \throw invalid_option
- */
-OPTIONS_EXPORT result read(int& argc, char**& argv, const options& definition);
-
-} // !option
-
-#endif // !OPTIONS_HPP
--- a/cpp/options/test/main.cpp	Wed Aug 01 13:56:54 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,233 +0,0 @@
-/*
- * main.cpp -- main test file for options
- *
- * Copyright (c) 2015-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#define BOOST_TEST_MODULE "Options"
-#include <boost/test/unit_test.hpp>
-
-#include <options.hpp>
-
-/*
- * Short options.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(short_options)
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-    std::vector<std::string> args{"-a", "-b"};
-
-    auto pack = option::read(args, {
-        { "-a", false },
-        { "-b", false }
-    });
-
-    BOOST_TEST(pack.size() == 2U);
-    BOOST_TEST(args.size() == 0U);
-    BOOST_TEST(pack.count("-a") != 0);
-    BOOST_TEST(pack.count("-b") != 0);
-}
-
-BOOST_AUTO_TEST_CASE(simple_arg)
-{
-    std::vector<std::string> args{"-v", "-cfoo.conf"};
-
-    auto pack = option::read(args, {
-        { "-v", false },
-        { "-c", true  }
-    });
-
-    BOOST_TEST(pack.size() == 2U);
-    BOOST_TEST(args.size() == 0U);
-    BOOST_TEST(pack.count("-v") != 0);
-    BOOST_TEST(pack.find("-c")->second == "foo.conf");
-}
-
-BOOST_AUTO_TEST_CASE(spaced_arg)
-{
-    std::vector<std::string> args{"-v", "-c", "foo.conf"};
-
-    auto pack = option::read(args, {
-        { "-v", false },
-        { "-c", true  }
-    });
-
-    BOOST_TEST(pack.size() == 2U);
-    BOOST_TEST(args.size() == 0U);
-    BOOST_TEST(pack.count("-v") != 0);
-    BOOST_TEST(pack.find("-c")->second == "foo.conf");
-}
-
-BOOST_AUTO_TEST_CASE(compacted)
-{
-    std::vector<std::string> args{"-abc"};
-
-    auto pack = option::read(args, {
-        { "-a", false },
-        { "-b", false },
-        { "-c", false },
-    });
-
-    BOOST_TEST(pack.size() == 3U);
-    BOOST_TEST(args.size() == 0U);
-    BOOST_TEST(pack.count("-a") != 0);
-    BOOST_TEST(pack.count("-b") != 0);
-    BOOST_TEST(pack.count("-c") != 0);
-}
-
-BOOST_AUTO_TEST_CASE(compacted_arg)
-{
-    std::vector<std::string> args{"-vdcfoo.conf"};
-
-    auto pack = option::read(args, {
-        { "-v", false },
-        { "-d", false },
-        { "-c", true },
-    });
-
-    BOOST_TEST(pack.size() == 3U);
-    BOOST_TEST(args.size() == 0U);
-    BOOST_TEST(pack.count("-v") != 0);
-    BOOST_TEST(pack.count("-d") != 0);
-    BOOST_TEST(pack.find("-c")->second == "foo.conf");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Long options.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(long_options)
-
-BOOST_AUTO_TEST_CASE(simple)
-{
-    std::vector<std::string> args{"--fullscreen"};
-
-    auto pack = option::read(args, {
-        { "--verbose",      false },
-        { "--fullscreen",   false }
-    });
-
-    BOOST_TEST(pack.size() == 1U);
-    BOOST_TEST(args.size() == 0U);
-    BOOST_TEST(pack.count("--fullscreen") != 0);
-}
-
-BOOST_AUTO_TEST_CASE(simple_arg)
-{
-    std::vector<std::string> args{"--config", "config.conf", "--level", "2"};
-
-    auto pack = option::read(args, {
-        { "--config",   true },
-        { "--level",    true }
-    });
-
-    BOOST_TEST(pack.size() == 2U);
-    BOOST_TEST(args.size() == 0U);
-    BOOST_TEST(pack.find("--config")->second == "config.conf");
-    BOOST_TEST(pack.find("--level")->second == "2");
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-/*
- * Errors.
- * ------------------------------------------------------------------
- */
-
-BOOST_AUTO_TEST_SUITE(errors)
-
-BOOST_AUTO_TEST_CASE(stop)
-{
-    std::vector<std::string> args{"-v", "install", "-y", "irccd"};
-    std::vector<std::string> expected{"install", "-y", "irccd"};
-
-    auto pack = option::read(args, {{ "-v", false }});
-
-    BOOST_TEST(pack.size() == 1U);
-    BOOST_TEST(args.size() == 3U);
-    BOOST_TEST(pack.count("-v") != 0);
-    BOOST_TEST(expected == args);
-}
-
-BOOST_AUTO_TEST_CASE(missing_short_arg)
-{
-    std::vector<std::string> args{"-c"};
-
-    BOOST_REQUIRE_THROW(option::read(args, {{ "-c", true }}), option::missing_value);
-}
-
-BOOST_AUTO_TEST_CASE(missing_short_arg2)
-{
-    const option::options options{
-        { "-v", false },
-        { "-c", true }
-    };
-
-    std::vector<std::string> args{"-vc"};
-
-    BOOST_REQUIRE_THROW(option::read(args, options), option::missing_value);
-}
-
-BOOST_AUTO_TEST_CASE(missing_long_arg)
-{
-    const option::options options{
-        { "--config", true }
-    };
-
-    std::vector<std::string> args{"--config"};
-
-    BOOST_REQUIRE_THROW(option::read(args, options), option::missing_value);
-}
-
-BOOST_AUTO_TEST_CASE(invalid_option)
-{
-    const option::options options{
-        { "-v", true }
-    };
-
-    std::vector<std::string> args{"-x"};
-
-    BOOST_REQUIRE_THROW(option::read(args, options), option::invalid_option);
-}
-
-BOOST_AUTO_TEST_CASE(invalid_option2)
-{
-    const option::options options{
-        { "--verbose", true }
-    };
-
-    std::vector<std::string> args{"--destroy"};
-
-    BOOST_REQUIRE_THROW(option::read(args, options), option::invalid_option);
-}
-
-BOOST_AUTO_TEST_CASE(invalid_option3)
-{
-    const option::options options{
-        { "-x", true }
-    };
-
-    std::vector<std::string> args{"-vx"};
-
-    BOOST_REQUIRE_THROW(option::read(args, options), option::invalid_option);
-}
-
-BOOST_AUTO_TEST_SUITE_END()