From aaf8823da055a804da78e635900aa8d52741c59f Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Tue, 4 Jun 2019 10:40:51 +0200 Subject: Fix 'multiple definition' link error if header is included multiple times in different files in a project. --- getoptpp.hpp | 155 +++++++++++++++++++++++++++-------------------------------- 1 file changed, 71 insertions(+), 84 deletions(-) diff --git a/getoptpp.hpp b/getoptpp.hpp index 1557206..09323a8 100644 --- a/getoptpp.hpp +++ b/getoptpp.hpp @@ -13,105 +13,92 @@ using Handle = std::function; class Options { public: - Options(); - /// @param name name of the option /// @param has_arg kind of arguments that are used (no_argument, required_argument, optional_argument) /// @param val identifies the option (see getopt documentation) /// @param handle lambda that is invoked when the option occures - void add(std::string const & name, int has_arg, int val, Handle handle); + void add(std::string const & name, int has_arg, int val, Handle handle) { + add(name, has_arg, nullptr, val, handle); + } /// @param name name of the option /// @param has_arg kind of arguments that are used (no_argument, required_argument, optional_argument) /// @param flag pointer that is set after the option occured /// @param val value for the flag to be set /// @param handle lambda that is invoked when the option occures - void add(std::string const & name, int has_arg, int* flag, int val, Handle handle); + void add(std::string const & name, int has_arg, int* flag, int val, Handle handle) { + // create a new option from the args + options.push_back({name.data(), has_arg, flag, val}); + + int index = val; // let val be the option's unique identifier + if (flag != nullptr) { + // flag is not null, so the val is not used as identifier + // so pick another one + index = num_flags++; + } + // store the handle + handles[index] = handle; + } + + bool process(int argc, char* argv[]) { + std::string shortopts; + for (auto const & option: options) { + if (option.flag != nullptr) { + continue; + } + shortopts += static_cast(option.val); + + switch (option.has_arg) { + case no_argument: + break; + case required_argument: + shortopts += ":"; + break; + case optional_argument: + shortopts += "::"; + break; + } + } + + // add termination option + options.push_back({0, 0, 0, 0}); + + // handle arguments + while (true) { + int index = 0; + int key = getopt_long(argc, argv, shortopts.data(), options.data(), &index); + + if (key == -1) { + break; + } else if (key == '?') { + return false; + } else if (key == ':') { + return false; + } else if (key == 0) { + // call flag's handle + handles.at(index)(); + } else { + // call option's handle + handles.at(key)(); + } + } + for (int i = optind; i < argc; ++i) { + args.push_back(argv[i]); + } + + // remove terminating option + options.pop_back(); + assert(options.size() == handles.size()); + return true; + } - bool process(int argc, char* argv[]); const std::vector arguments() const { return args; } private: - std::size_t num_flags; - std::vector