Home | History | Annotate | Download | only in libopt++
      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 
     45 	virtual ~option_base() {}
     46 
     47 	/**
     48 	 * post_process - perform any necessary post-processing
     49 	 */
     50 	virtual void post_process() {}
     51 
     52 protected:
     53 	char const * option_name;
     54 };
     55 
     56 
     57 /** the popt array singleton options */
     58 static vector<poptOption> & popt_options(void)
     59 {
     60 	static vector<poptOption> *x = new(vector<poptOption>);
     61 	return *x;
     62 }
     63 
     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 */
     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 
    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 
    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 
    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 
    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 
    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 
    206 option::~option()
    207 {
    208 	delete the_option;
    209 }
    210 
    211 
    212 /// non templatized ctor for boolean option
    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 <>
    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 <>
    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 <>
    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 
    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 
    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 
    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 
    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 
    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 
    298 void option_imp<string>::post_process()
    299 {
    300 	if (popt_value) {
    301 		value = popt_value;
    302 		popt_value = 0;
    303 	}
    304 }
    305 
    306 
    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 
    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