diff options
author | Christian Glöckner <cgloeckner@freenet.de> | 2016-03-29 08:30:06 +0200 |
---|---|---|
committer | Christian Glöckner <cgloeckner@freenet.de> | 2016-03-29 08:30:06 +0200 |
commit | 940e1b410343f423a9bc41ca8da0c3859e2333fc (patch) | |
tree | 8a476099bb5fb6276aa6d7108d64e229773efbd9 | |
parent | 2c15690b221f151d071512f828a60ac58030c33f (diff) |
Initial implementation
-rw-r--r-- | .gitignore | 29 | ||||
-rw-r--r-- | example.cpp | 35 | ||||
-rw-r--r-- | getoptpp.hpp | 96 |
3 files changed, 132 insertions, 28 deletions
@@ -1,28 +1 @@ -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app +getoptpp.geany diff --git a/example.cpp b/example.cpp new file mode 100644 index 0000000..c99f3e7 --- /dev/null +++ b/example.cpp @@ -0,0 +1,35 @@ +#include <iostream> + +#include "getoptpp.hpp" + +int main(int argc, char* argv[]) { + int verbose_flag; + + gopt::Options opt; + opt.add("verbose", no_argument, &verbose_flag, 1, [&]() { + std::cout << "verbose: " << verbose_flag << "\n"; + }); + opt.add("brief", no_argument, &verbose_flag, 0, [&]() { + std::cout << "brief: " << verbose_flag << "\n"; + }); + opt.add("add", no_argument, 'a', [&]() { + std::cout << "add\n"; + }); + opt.add("append", no_argument, 'b', [&]() { + std::cout << "append\n"; + }); + opt.add("delete", required_argument, 'd', [&]() { + std::cout << "delete: " << optarg << "\n"; + }); + opt.add("create", required_argument, 'c', [&]() { + std::cout << "create: " << optarg << "\n"; + }); + opt.add("file", required_argument, 'f', [&]() { + std::cout << "file: " << optarg << "\n"; + }); + opt.add("help", no_argument, '?', [&]() { + std::cout << "usage stuff\n"; + }); + + opt.process(argc, argv); +} diff --git a/getoptpp.hpp b/getoptpp.hpp new file mode 100644 index 0000000..4fe3c3a --- /dev/null +++ b/getoptpp.hpp @@ -0,0 +1,96 @@ +#pragma once +#include <cassert> +#include <functional> +#include <vector> +#include <unordered_map> +#include <getopt.h> + +namespace gopt { + +using Handle = std::function<void()>; + +class Options { + public: + Options(); + + void add(std::string const & name, int has_arg, int val, Handle handle); + void add(std::string const & name, int has_arg, int* flag, int val, Handle handle); + + void process(int argc, char* argv[]); + + private: + std::size_t num_flags; + std::vector<option> options; + std::unordered_map<int, Handle> handles; +}; + +Options::Options() + : num_flags{} + , options{} + , handles{} { +} + +void Options::add(std::string const & name, int has_arg, int val, Handle handle) { + add(name, has_arg, nullptr, val, handle); +} + +void Options::add(std::string const & name, int has_arg, int* flag, int val, Handle handle) { + options.emplace_back(); + auto& option = options.back(); + option.name = name.c_str(); + option.has_arg = has_arg; + option.flag = flag; + option.val = val; + + int index = val; + if (flag != nullptr) { + index = num_flags++; + } + handles[index] = handle; +} + +void Options::process(int argc, char* argv[]) { + std::string shortopts; + for (auto const & option: options) { + if (option.flag != nullptr) { + continue; + } + shortopts += static_cast<char>(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.c_str(), options.data(), &index); + + if (key == -1) { + break; + } else if (key == 0) { + // call flag's handle + handles.at(index)(); + } else { + // call option's handle + handles.at(key)(); + } + } + + // remove terminating option + options.pop_back(); + assert(options.size() == handles.size()); +} + +} |