diff options
Diffstat (limited to 'kms++util/opts.cpp')
-rw-r--r-- | kms++util/opts.cpp | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/kms++util/opts.cpp b/kms++util/opts.cpp new file mode 100644 index 0000000..4ea31f8 --- /dev/null +++ b/kms++util/opts.cpp @@ -0,0 +1,117 @@ +#include <algorithm> + +#include <unistd.h> +#include <getopt.h> + +#include "opts.h" + +using namespace std; + +Option::Option(const string& str, function<void()> func) + : m_void_func(func) +{ + parse(str); +} + +Option::Option(const string& str, function<void(const string)> func) + : m_func(func) +{ + parse(str); +} + +void Option::parse(const string& str) +{ + auto iend = str.end(); + if (*(iend - 1) == '=') { + iend--; + m_has_arg = 1; + } else if (*(iend - 1) == '?') { + iend--; + m_has_arg = 2; + } else { + m_has_arg = 0; + } + + auto isplit = find(str.begin(), iend, '|'); + + if (isplit != str.begin()) + m_short = str[0]; + else + m_short = 0; + + if (isplit != iend) + m_long = string(isplit + 1, iend); +} + +OptionSet::OptionSet(initializer_list<Option> il) + : m_opts(il) +{ +} + +void OptionSet::parse(int argc, char** argv) +{ + string shortopts = ":"; + vector<struct option> longopts; + + for (unsigned opt_idx = 0; opt_idx < m_opts.size(); ++opt_idx) { + const Option& o = m_opts[opt_idx]; + + if (o.m_short != 0) { + shortopts.push_back(o.m_short); + if (o.m_has_arg == 1) + shortopts.push_back(':'); + else if (o.m_has_arg == 2) + shortopts.append("::"); + } + + if (!o.m_long.empty()) { + struct option copt; + copt.name = o.m_long.c_str(); + copt.has_arg = o.m_has_arg; + copt.flag = 0; + copt.val = opt_idx + 1000; + longopts.push_back(copt); + } + } + + longopts.push_back(option {}); + + while (1) { + int long_idx = 0; + int c = getopt_long(argc, argv, shortopts.c_str(), + longopts.data(), &long_idx); + if (c == -1) + break; + + if (c == '?') + throw std::invalid_argument(string("Unrecognized option ") + argv[optind - 1]); + + if (c == ':') { + const Option& o = find_opt(optopt); + if (optopt < 256) + throw std::invalid_argument(string("Missing argument to -") + o.m_short); + else + throw std::invalid_argument(string("Missing argument to --") + o.m_long); + } + + string sarg = { optarg ?: "" }; + + const Option& opt = find_opt(c); + + if (opt.m_func) + opt.m_func(sarg); + else + opt.m_void_func(); + } + + for (int i = optind; i < argc; ++i) + m_params.push_back(argv[i]); +} + +const Option& OptionSet::find_opt(int c) +{ + if (c < 256) + return *find_if(m_opts.begin(), m_opts.end(), [c](const Option& o) { return o.m_short == c; }); + else + return m_opts[c - 1000]; +} |