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