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
Option(const string & str,function<void ()> func)10 Option::Option(const string& str, function<void()> func)
11 : m_void_func(func)
12 {
13 parse(str);
14 }
15
Option(const string & str,function<void (const string)> func)16 Option::Option(const string& str, function<void(const string)> func)
17 : m_func(func)
18 {
19 parse(str);
20 }
21
parse(const string & str)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
OptionSet(initializer_list<Option> il)46 OptionSet::OptionSet(initializer_list<Option> il)
47 : m_opts(il)
48 {
49 }
50
parse(int argc,char ** argv)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
find_opt(int c)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 }
118