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