summaryrefslogtreecommitdiffstats
path: root/include/diargs.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/diargs.hpp')
-rw-r--r--include/diargs.hpp177
1 files changed, 177 insertions, 0 deletions
diff --git a/include/diargs.hpp b/include/diargs.hpp
new file mode 100644
index 0000000..ee5cf63
--- /dev/null
+++ b/include/diargs.hpp
@@ -0,0 +1,177 @@
+/**
+ * diargs.hpp
+ * Copyright (c) 2022 Jon Santmyer <jon@jonsantmyer.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * diargs - An alternative to GNU getopt for modern C++
+ * Provides tools to parse command line arguments for C++17 programs
+ *
+ * Usage: Instantiate an ArgumentParser class, passing in a fallback
+ * error function, an ArgumentList struct, and an argc,argv pair.
+ *
+ * Example:
+ *
+ * void printusage(int err) {
+ * std::cout << "-h --help : Print this message" << std::endl;
+ * std::exit(err);
+ * }
+ *
+ * int main(int argc, char **argv) {
+ * bool helpflag;
+ *
+ * ArgsPair args{argc, argv};
+ * ArgumentList argslist(
+ * ToggleArgument("help", 'h', helpflag, true)
+ * );
+ * ArgumentParser parser(printusage, argslist, args);
+ * return 0;
+ * }
+ */
+#ifndef DIARGS_HPP
+#define DIARGS_HPP 1
+
+#include <string>
+#include <sstream>
+#include <vector>
+#include <memory>
+#include <optional>
+#include <algorithm>
+
+namespace diargs {
+
+ /*Passed to ArgumentParser*/
+ struct ArgsPair {
+ int argc {};
+ char **argv {};
+ };
+
+ /*Interface for argument types. Makes the whole system tick*/
+ struct IArgument
+ {
+ std::string longform {}; /*Name parsed when passed through with '--'*/
+ char shortform {}; /*Character parsed when passed through with '-'*/
+
+ IArgument() = default;
+ IArgument(const std::string &Longform, char Shortform) :
+ longform(Longform), shortform(Shortform) {}
+ virtual ~IArgument() = default;
+
+ virtual std::optional<std::vector<std::string_view>::iterator> parse(
+ std::vector<std::string_view> &argv,
+ std::vector<std::string_view>::iterator arg) = 0;
+ };
+
+ template<typename T>
+ struct MultiArgument : public IArgument
+ {
+ T *flag; /*Value set when encountered. Taken from next argument
+ i.e. --arg [VALUE]*/
+
+ MultiArgument(T &Flag) : flag(&Flag) {}
+ MultiArgument(const std::string &Longform, T &Flag) :
+ IArgument(Longform, 0), flag(&Flag) {}
+ MultiArgument(const std::string &Longform, char Shortform, T &Flag) :
+ IArgument(Longform, Shortform), flag(&Flag) {}
+ ~MultiArgument() {}
+
+ std::optional<std::vector<std::string_view>::iterator> parse(
+ std::vector<std::string_view> &argv,
+ std::vector<std::string_view>::iterator arg) {
+ if(++arg == argv.end()) return std::nullopt; /*Not having the
+ value is an error case*/
+ std::stringstream ss((*arg).data());
+ ss >> std::noskipws >> *flag;
+ return arg;
+ }
+ };
+
+ template<typename T>
+ struct ToggleArgument : public IArgument
+ {
+ T *flag; /*Value set to [set] when encountered*/
+ T set; /*Value that [flag] is set to when parsed*/
+
+ ToggleArgument(T &Flag, const T Set) :
+ flag(&Flag), set(Set) {}
+ ToggleArgument(const std::string &Longform, T &Flag, const T Set) :
+ IArgument(Longform, 0), flag(&Flag), set(&Set) {}
+ ToggleArgument(const std::string &Longform, char Shortform,
+ T &Flag, const T Set) :
+ IArgument(Longform, Shortform), flag(&Flag), set(&Set) {}
+ ~ToggleArgument() {}
+
+ std::optional<std::vector<std::string_view>::iterator> parse(
+ std::vector<std::string_view> &argv,
+ std::vector<std::string_view>::iterator arg) {
+ *flag = set;
+ return arg;
+ }
+ };
+
+ /*Type for values not denoted with '-' or '--'*/
+ template<typename T>
+ struct OrderedArgument : public IArgument
+ {
+ T *flag; /*Value set when passed arg is not any other type*/
+ std::optional<T> dflt;
+ OrderedArgument(T &Flag) :
+ flag(&Flag), dflt(std::nullopt) {}
+ OrderedArgument(T &Flag, T Dflt) :
+ flag(&Flag), dflt(Dflt) {}
+ ~OrderedArgument() {}
+ std::optional<std::vector<std::string_view>::iterator> parse(
+ std::vector<std::string_view> &argv,
+ std::vector<std::string_view>::iterator arg) {
+ std::stringstream ss((*arg).data());
+ ss >> std::noskipws >> *flag;
+ return arg;
+ }
+ };
+
+ /*Container for argument checking*/
+ struct ArgumentList
+ {
+ std::vector<std::unique_ptr<IArgument>> arguments;
+
+ void addArgument() {}
+ template<class T, class... ArgumentPack>
+ void addArgument(T arg, ArgumentPack... args) {
+ arguments.push_back(std::make_unique<T>(arg));
+ addArgument(args...);
+ }
+
+ template<class... ArgumentPack>
+ ArgumentList(ArgumentPack... arguments) {
+ addArgument(arguments...);
+ }
+ };
+
+ /*Instantiation results in parsed arguments*/
+ class ArgumentParser
+ {
+ public:
+ ArgumentParser(
+ void (*failfunc)(int),
+ ArgumentList &arguments,
+ ArgsPair argcv);
+ };
+}
+
+#endif