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