aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'kms++util/src/opts.cpp')
-rw-r--r--kms++util/src/opts.cpp117
1 files changed, 117 insertions, 0 deletions
diff --git a/kms++util/src/opts.cpp b/kms++util/src/opts.cpp
new file mode 100644
index 0000000..afef452
--- /dev/null
+++ b/kms++util/src/opts.cpp
@@ -0,0 +1,117 @@
1#include <algorithm>
2
3#include <unistd.h>
4#include <getopt.h>
5
6#include <kms++util/opts.h>
7
8using namespace std;
9
10Option::Option(const string& str, function<void()> func)
11 : m_void_func(func)
12{
13 parse(str);
14}
15
16Option::Option(const string& str, function<void(const string)> func)
17 : m_func(func)
18{
19 parse(str);
20}
21
22void Option::parse(const string& str)
23{
24 auto iend = str.end();
25 if (*(iend - 1) == '=') {
26 iend--;
27 m_has_arg = 1;
28 } else if (*(iend - 1) == '?') {
29 iend--;
30 m_has_arg = 2;
31 } else {
32 m_has_arg = 0;
33 }
34
35 auto isplit = find(str.begin(), iend, '|');
36
37 if (isplit != str.begin())
38 m_short = str[0];
39 else
40 m_short = 0;
41
42 if (isplit != iend)
43 m_long = string(isplit + 1, iend);
44}
45
46OptionSet::OptionSet(initializer_list<Option> il)
47 : m_opts(il)
48{
49}
50
51void OptionSet::parse(int argc, char** argv)
52{
53 string shortopts = ":";
54 vector<struct option> longopts;
55
56 for (unsigned opt_idx = 0; opt_idx < m_opts.size(); ++opt_idx) {
57 const Option& o = m_opts[opt_idx];
58
59 if (o.m_short != 0) {
60 shortopts.push_back(o.m_short);
61 if (o.m_has_arg == 1)
62 shortopts.push_back(':');
63 else if (o.m_has_arg == 2)
64 shortopts.append("::");
65 }
66
67 if (!o.m_long.empty()) {
68 struct option copt;
69 copt.name = o.m_long.c_str();
70 copt.has_arg = o.m_has_arg;
71 copt.flag = 0;
72 copt.val = opt_idx + 1000;
73 longopts.push_back(copt);
74 }
75 }
76
77 longopts.push_back(option {});
78
79 while (1) {
80 int long_idx = 0;
81 int c = getopt_long(argc, argv, shortopts.c_str(),
82 longopts.data(), &long_idx);
83 if (c == -1)
84 break;
85
86 if (c == '?')
87 throw std::invalid_argument(string("Unrecognized option ") + argv[optind - 1]);
88
89 if (c == ':') {
90 const Option& o = find_opt(optopt);
91 if (optopt < 256)
92 throw std::invalid_argument(string("Missing argument to -") + o.m_short);
93 else
94 throw std::invalid_argument(string("Missing argument to --") + o.m_long);
95 }
96
97 string sarg = { optarg ?: "" };
98
99 const Option& opt = find_opt(c);
100
101 if (opt.m_func)
102 opt.m_func(sarg);
103 else
104 opt.m_void_func();
105 }
106
107 for (int i = optind; i < argc; ++i)
108 m_params.push_back(argv[i]);
109}
110
111const Option& OptionSet::find_opt(int c)
112{
113 if (c < 256)
114 return *find_if(m_opts.begin(), m_opts.end(), [c](const Option& o) { return o.m_short == c; });
115 else
116 return m_opts[c - 1000];
117}