• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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