blob: 53a8c80de8c9186315eb512c7542a90b3bb3ebb4 [file] [log] [blame]
Mike Dodd8cfa7022010-11-17 11:12:26 -08001/**
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
20using namespace std;
21
22namespace 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 */
30class option_base {
31public:
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
45 virtual ~option_base() {}
46
47 /**
48 * post_process - perform any necessary post-processing
49 */
50 virtual void post_process() {}
51
52protected:
53 char const * option_name;
54};
55
56
57/** the popt array singleton options */
58static vector<poptOption> & popt_options(void)
59{
60 static vector<poptOption> *x = new(vector<poptOption>);
61 return *x;
62}
63
64static vector<option_base *> & options_list(void)
65{
66 static vector<option_base *> *x = new(vector<option_base *>);
67 return *x;
68}
69
70static int showvers;
71
72static 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 */
81static 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
109void 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
121template <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 */
130template <> class option_imp<void> : public option_base {
131public:
132 option_imp(bool & value, char const * option_name, char short_name,
133 char const * help_str);
134
135 ~option_imp() {}
136
137 void post_process();
138
139private:
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 */
150template <> class option_imp<int> : public option_base {
151public:
152 option_imp(int & value, char const * option_name, char short_name,
153 char const * help_str, char const * arg_help_str);
154
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 */
164template <> class option_imp<string> : public option_base {
165public:
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
172 ~option_imp() {}
173
174private:
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 */
187template <> class option_imp< vector<string> > : public option_base {
188public:
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
196 ~option_imp() {}
197
198private:
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
206option::~option()
207{
208 delete the_option;
209}
210
211
212/// non templatized ctor for boolean option
213option::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
220template <>
221option::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
230template <>
231option::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
240template <>
241option::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
249option_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
263option_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
271void 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
282option_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
289option_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
298void option_imp<string>::post_process()
299{
300 if (popt_value) {
301 value = popt_value;
302 popt_value = 0;
303 }
304}
305
306
307option_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
318void 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