summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Glöckner <cgloeckner@freenet.de>2016-03-29 06:30:06 (GMT)
committerChristian Glöckner <cgloeckner@freenet.de>2016-03-29 06:30:06 (GMT)
commit940e1b410343f423a9bc41ca8da0c3859e2333fc (patch)
tree8a476099bb5fb6276aa6d7108d64e229773efbd9
parent2c15690b221f151d071512f828a60ac58030c33f (diff)
Initial implementation
-rw-r--r--.gitignore29
-rw-r--r--example.cpp35
-rw-r--r--getoptpp.hpp96
3 files changed, 132 insertions, 28 deletions
diff --git a/.gitignore b/.gitignore
index b8bd026..bc98fd3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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());
+}
+
+}