diff options
Diffstat (limited to 'kms++util/src/opts.cpp')
-rw-r--r-- | kms++util/src/opts.cpp | 117 |
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 | |||
8 | using namespace std; | ||
9 | |||
10 | Option::Option(const string& str, function<void()> func) | ||
11 | : m_void_func(func) | ||
12 | { | ||
13 | parse(str); | ||
14 | } | ||
15 | |||
16 | Option::Option(const string& str, function<void(const string)> func) | ||
17 | : m_func(func) | ||
18 | { | ||
19 | parse(str); | ||
20 | } | ||
21 | |||
22 | void 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 | |||
46 | OptionSet::OptionSet(initializer_list<Option> il) | ||
47 | : m_opts(il) | ||
48 | { | ||
49 | } | ||
50 | |||
51 | void 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 | |||
111 | const 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 | } | ||