popt_options.cpp revision cc2ee177dbb3befca43e36cfc56778b006c3d050
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
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;
59static vector<option_base *> options_list;
60
61static int showvers;
62
63static struct poptOption appended_options[] = {
64	{ "version", 'v', POPT_ARG_NONE, &showvers, 0, "show version", NULL, },
65	POPT_AUTOHELP
66	POPT_TABLEEND
67	};
68
69
70/* options parameter can't be a local variable because caller can use the
71 * returned poptContext which contains  pointer inside the options array */
72static poptContext do_parse_options(int argc, char const ** argv,
73                                    vector<poptOption> & options,
74                                    vector<string> & additional_params)
75{
76	options = popt_options;
77
78	int const nr_appended_options =
79		sizeof(appended_options) / sizeof(appended_options[0]);
80
81	options.insert(options.end(), appended_options,
82		       appended_options + nr_appended_options);
83
84	poptContext con = op_poptGetContext(NULL, argc, argv, &options[0], 0);
85
86	if (showvers) {
87		show_version(argv[0]);
88	}
89
90	char const * file;
91	while ((file = poptGetArg(con)) != 0) {
92		additional_params.push_back(file);
93	}
94
95	for (size_t i = 0 ; i < options_list.size() ; ++i) {
96		options_list[i]->post_process();
97	}
98
99	return con;
100}
101
102
103void parse_options(int argc, char const ** argv,
104                   vector<string> & additional_params)
105{
106	vector<poptOption> options;
107
108	poptContext con =
109		do_parse_options(argc, argv, options, additional_params);
110
111	poptFreeContext(con);
112}
113
114
115template <typename T> class option_imp;
116
117
118/**
119 * option<void> - a binary option
120 *
121 * Use this option type for constructing specified / not-specified
122 * options e.g. --frob
123 */
124template <> class option_imp<void> : public option_base {
125public:
126	option_imp(bool & value, char const * option_name, char short_name,
127	           char const * help_str);
128
129	~option_imp() {}
130
131	void post_process();
132
133private:
134	bool & value;
135	int popt_value;
136};
137
138
139/**
140 * option<int> - a integer option
141 *
142 * Use this for options taking an integer e.g. --frob 6
143 */
144template <> class option_imp<int> : public option_base {
145public:
146	option_imp(int & value, char const * option_name, char short_name,
147	           char const * help_str, char const * arg_help_str);
148
149	~option_imp() {}
150};
151
152
153/**
154 * option<string> - a string option
155 *
156 * Use this for options taking a string e.g. --frob parsley
157 */
158template <> class option_imp<string> : public option_base {
159public:
160	option_imp(string & value, char const * option_name,
161	           char short_name, char const * help_str,
162	           char const * arg_help_str);
163
164	void post_process();
165
166	~option_imp() {}
167
168private:
169	// we need an intermediate char array to pass to popt libs
170	char * popt_value;
171	string & value;
172};
173
174
175/**
176 * option< vector<string> > - a string vector option
177 *
178 * Use this for options taking a number of string arguments,
179 * separated by the given separator.
180 */
181template <> class option_imp< vector<string> > : public option_base {
182public:
183	option_imp(vector<string> & value,
184	           char const * option_name, char short_name,
185	           char const * help_str, char const * arg_help_str,
186	           char separator = ',');
187
188	void post_process();
189
190	~option_imp() {}
191
192private:
193	vector<string> & value;
194	// we need an intermediate char array to pass to popt libs
195	char * popt_value;
196	char const separator;
197};
198
199
200option::~option()
201{
202	delete the_option;
203}
204
205
206/// non templatized ctor for boolean option
207option::option(bool & value, char const * name, char short_name, char const * help)
208	: the_option(new option_imp<void>(value, name, short_name, help))
209{
210}
211
212
213/// specialization of option ctor for integer option
214template <>
215option::option(int & value, char const * name, char short_name,
216               char const * help, char const * arg_help)
217	: the_option(new option_imp<int>
218			(value, name, short_name, help, arg_help))
219{
220}
221
222
223/// specialization of option ctor for string option
224template <>
225option::option(string & value, char const * name, char short_name,
226               char const * help, char const * arg_help)
227	: the_option(new option_imp<string>
228			(value, name, short_name, help, arg_help))
229{
230}
231
232
233/// specialization of option ctor for vector<string> option
234template <>
235option::option(vector<string> & value, char const * name, char short_name,
236               char const * help, char const * arg_help)
237	: the_option(new option_imp< vector<string> >
238			(value, name, short_name, help, arg_help))
239{
240}
241
242
243option_base::option_base(char const * name, char short_name,
244                         char const * help, char const * arg_help,
245                         void * data, int popt_flags)
246	: option_name(name)
247{
248	poptOption const opt = { name, short_name, popt_flags,
249	                         data, 0, help, arg_help };
250
251	popt_options.push_back(opt);
252
253	options_list.push_back(this);
254}
255
256
257option_imp<void>::option_imp(bool & val, char const * name, char short_name,
258                             char const * help)
259	: option_base(name, short_name, help, 0, &popt_value, POPT_ARG_NONE),
260	  value(val), popt_value(0)
261{
262}
263
264
265void option_imp<void>::post_process()
266{
267	if (popt_value) {
268		if (is_prefix(option_name, "no-"))
269			value = !popt_value;
270		else
271			value = popt_value;
272	}
273}
274
275
276option_imp<int>::option_imp(int & value, char const * name, char short_name,
277                            char const * help, char const * arg_help)
278	: option_base(name, short_name, help, arg_help, &value, POPT_ARG_INT)
279{
280}
281
282
283option_imp<string>::option_imp(string & val, char const * name, char short_name,
284                               char const * help, char const * arg_help)
285	: option_base(name, short_name, help, arg_help,
286                      &popt_value, POPT_ARG_STRING),
287	  popt_value(0), value(val)
288{
289}
290
291
292void option_imp<string>::post_process()
293{
294	if (popt_value) {
295		value = popt_value;
296		popt_value = 0;
297	}
298}
299
300
301option_imp< vector<string> >::option_imp(vector<string> & val,
302                                         char const * name, char short_name,
303                                         char const * help,
304                                         char const * arg_help, char sepchar)
305	: option_base(name, short_name, help, arg_help,
306	              &popt_value, POPT_ARG_STRING),
307	  value(val), popt_value(0), separator(sepchar)
308{
309}
310
311
312void option_imp< vector<string> >::post_process()
313{
314	if (popt_value) {
315		value = separate_token(popt_value, separator);
316
317		popt_value = 0;
318	}
319}
320
321} // namespace popt
322