1 /**
2 * @file popt_options.cpp
3 * option parsing
4 *
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author Philippe Elie
9 * @author John Levon
10 */
11
12 #include <iostream>
13
14 #include "op_popt.h"
15 #include "op_version.h"
16
17 #include "popt_options.h"
18 #include "string_manip.h"
19
20 using namespace std;
21
22 namespace popt {
23
24 /**
25 * option_base - base class for implementation of a command line option
26 *
27 * Every command line option added before calling parse_options()
28 * is of this type.
29 */
30 class option_base {
31 public:
32 /**
33 * option_base - construct an option with the given options.
34 * @param option_name name part of long form e.g. --option
35 * @param short_name short form name e.g. -o
36 * @param help_str short description of the option
37 * @param arg_help_str short description of the argument (if any)
38 * @param data a pointer to the data to fill in
39 * @param popt_flags the popt library data type
40 */
41 option_base(char const * option_name, char short_name,
42 char const * help_str, char const * arg_help_str,
43 void * data, int popt_flags);
44
~option_base()45 virtual ~option_base() {}
46
47 /**
48 * post_process - perform any necessary post-processing
49 */
post_process()50 virtual void post_process() {}
51
52 protected:
53 char const * option_name;
54 };
55
56
57 /** the popt array singleton options */
popt_options(void)58 static vector<poptOption> & popt_options(void)
59 {
60 static vector<poptOption> *x = new(vector<poptOption>);
61 return *x;
62 }
63
options_list(void)64 static vector<option_base *> & options_list(void)
65 {
66 static vector<option_base *> *x = new(vector<option_base *>);
67 return *x;
68 }
69
70 static int showvers;
71
72 static struct poptOption appended_options[] = {
73 { "version", 'v', POPT_ARG_NONE, &showvers, 0, "show version", NULL, },
74 POPT_AUTOHELP
75 POPT_TABLEEND
76 };
77
78
79 /* options parameter can't be a local variable because caller can use the
80 * returned poptContext which contains pointer inside the options array */
do_parse_options(int argc,char const ** argv,vector<poptOption> & options,vector<string> & additional_params)81 static poptContext do_parse_options(int argc, char const ** argv,
82 vector<poptOption> & options,
83 vector<string> & additional_params)
84 {
85 options = popt_options();
86
87 int const nr_appended_options =
88 sizeof(appended_options) / sizeof(appended_options[0]);
89
90 options.insert(options.end(), appended_options,
91 appended_options + nr_appended_options);
92
93 poptContext con = op_poptGetContext(NULL, argc, argv, &options[0], 0);
94
95 if (showvers)
96 show_version(argv[0]);
97
98 char const * file;
99 while ((file = poptGetArg(con)) != 0)
100 additional_params.push_back(file);
101
102 for (size_t i = 0 ; i < options_list().size() ; ++i)
103 options_list()[i]->post_process();
104
105 return con;
106 }
107
108
parse_options(int argc,char const ** argv,vector<string> & additional_params)109 void parse_options(int argc, char const ** argv,
110 vector<string> & additional_params)
111 {
112 vector<poptOption> options;
113
114 poptContext con =
115 do_parse_options(argc, argv, options, additional_params);
116
117 poptFreeContext(con);
118 }
119
120
121 template <typename T> class option_imp;
122
123
124 /**
125 * option<void> - a binary option
126 *
127 * Use this option type for constructing specified / not-specified
128 * options e.g. --frob
129 */
130 template <> class option_imp<void> : public option_base {
131 public:
132 option_imp(bool & value, char const * option_name, char short_name,
133 char const * help_str);
134
~option_imp()135 ~option_imp() {}
136
137 void post_process();
138
139 private:
140 bool & value;
141 int popt_value;
142 };
143
144
145 /**
146 * option<int> - a integer option
147 *
148 * Use this for options taking an integer e.g. --frob 6
149 */
150 template <> class option_imp<int> : public option_base {
151 public:
152 option_imp(int & value, char const * option_name, char short_name,
153 char const * help_str, char const * arg_help_str);
154
~option_imp()155 ~option_imp() {}
156 };
157
158
159 /**
160 * option<string> - a string option
161 *
162 * Use this for options taking a string e.g. --frob parsley
163 */
164 template <> class option_imp<string> : public option_base {
165 public:
166 option_imp(string & value, char const * option_name,
167 char short_name, char const * help_str,
168 char const * arg_help_str);
169
170 void post_process();
171
~option_imp()172 ~option_imp() {}
173
174 private:
175 // we need an intermediate char array to pass to popt libs
176 char * popt_value;
177 string & value;
178 };
179
180
181 /**
182 * option< vector<string> > - a string vector option
183 *
184 * Use this for options taking a number of string arguments,
185 * separated by the given separator.
186 */
187 template <> class option_imp< vector<string> > : public option_base {
188 public:
189 option_imp(vector<string> & value,
190 char const * option_name, char short_name,
191 char const * help_str, char const * arg_help_str,
192 char separator = ',');
193
194 void post_process();
195
~option_imp()196 ~option_imp() {}
197
198 private:
199 vector<string> & value;
200 // we need an intermediate char array to pass to popt libs
201 char * popt_value;
202 char const separator;
203 };
204
205
~option()206 option::~option()
207 {
208 delete the_option;
209 }
210
211
212 /// non templatized ctor for boolean option
option(bool & value,char const * name,char short_name,char const * help)213 option::option(bool & value, char const * name, char short_name, char const * help)
214 : the_option(new option_imp<void>(value, name, short_name, help))
215 {
216 }
217
218
219 /// specialization of option ctor for integer option
220 template <>
option(int & value,char const * name,char short_name,char const * help,char const * arg_help)221 option::option(int & value, char const * name, char short_name,
222 char const * help, char const * arg_help)
223 : the_option(new option_imp<int>
224 (value, name, short_name, help, arg_help))
225 {
226 }
227
228
229 /// specialization of option ctor for string option
230 template <>
option(string & value,char const * name,char short_name,char const * help,char const * arg_help)231 option::option(string & value, char const * name, char short_name,
232 char const * help, char const * arg_help)
233 : the_option(new option_imp<string>
234 (value, name, short_name, help, arg_help))
235 {
236 }
237
238
239 /// specialization of option ctor for vector<string> option
240 template <>
option(vector<string> & value,char const * name,char short_name,char const * help,char const * arg_help)241 option::option(vector<string> & value, char const * name, char short_name,
242 char const * help, char const * arg_help)
243 : the_option(new option_imp< vector<string> >
244 (value, name, short_name, help, arg_help))
245 {
246 }
247
248
option_base(char const * name,char short_name,char const * help,char const * arg_help,void * data,int popt_flags)249 option_base::option_base(char const * name, char short_name,
250 char const * help, char const * arg_help,
251 void * data, int popt_flags)
252 : option_name(name)
253 {
254 poptOption const opt = { name, short_name, popt_flags,
255 data, 0, help, arg_help };
256
257 popt_options().push_back(opt);
258
259 options_list().push_back(this);
260 }
261
262
option_imp(bool & val,char const * name,char short_name,char const * help)263 option_imp<void>::option_imp(bool & val, char const * name, char short_name,
264 char const * help)
265 : option_base(name, short_name, help, 0, &popt_value, POPT_ARG_NONE),
266 value(val), popt_value(0)
267 {
268 }
269
270
post_process()271 void option_imp<void>::post_process()
272 {
273 if (popt_value) {
274 if (is_prefix(option_name, "no-"))
275 value = !popt_value;
276 else
277 value = popt_value;
278 }
279 }
280
281
option_imp(int & value,char const * name,char short_name,char const * help,char const * arg_help)282 option_imp<int>::option_imp(int & value, char const * name, char short_name,
283 char const * help, char const * arg_help)
284 : option_base(name, short_name, help, arg_help, &value, POPT_ARG_INT)
285 {
286 }
287
288
option_imp(string & val,char const * name,char short_name,char const * help,char const * arg_help)289 option_imp<string>::option_imp(string & val, char const * name, char short_name,
290 char const * help, char const * arg_help)
291 : option_base(name, short_name, help, arg_help,
292 &popt_value, POPT_ARG_STRING),
293 popt_value(0), value(val)
294 {
295 }
296
297
post_process()298 void option_imp<string>::post_process()
299 {
300 if (popt_value) {
301 value = popt_value;
302 popt_value = 0;
303 }
304 }
305
306
option_imp(vector<string> & val,char const * name,char short_name,char const * help,char const * arg_help,char sepchar)307 option_imp< vector<string> >::option_imp(vector<string> & val,
308 char const * name, char short_name,
309 char const * help,
310 char const * arg_help, char sepchar)
311 : option_base(name, short_name, help, arg_help,
312 &popt_value, POPT_ARG_STRING),
313 value(val), popt_value(0), separator(sepchar)
314 {
315 }
316
317
post_process()318 void option_imp< vector<string> >::post_process()
319 {
320 if (popt_value) {
321 value = separate_token(popt_value, separator);
322
323 popt_value = 0;
324 }
325 }
326
327 } // namespace popt
328