Mike Dodd | 8cfa702 | 2010-11-17 11:12:26 -0800 | [diff] [blame^] | 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 |