00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "panda_getopt_impl.h"
00016 #include "pvector.h"
00017
00018 #if defined(HAVE_GETOPT) && defined(HAVE_GETOPT_LONG_ONLY)
00019
00020
00021
00022
00023 #else
00024
00025
00026
00027
00028 char *optarg = NULL;
00029 int optind = 0;
00030 int opterr = 1;
00031 int optopt = 0;
00032
00033
00034
00035
00036
00037
00038
00039
00040 class PandaGetopt {
00041 public:
00042 PandaGetopt(int argc, char *const argv[], const char *optstring,
00043 const struct option *longopts, bool allow_one_hyphen_long);
00044
00045 void permute(int argc, char **mutable_argv);
00046 int process(int opterr, int *longindex, char *&optarg, int &optind, int &optopt);
00047
00048 private:
00049 size_t find_short_option(char short_option);
00050 size_t find_long_option(const string &long_option);
00051
00052 void scan_options(const char *optstring, const struct option *longopts);
00053 void scan_args(int argc, char *const argv[]);
00054
00055
00056
00057
00058
00059
00060 class Option {
00061 public:
00062 Option(char short_option, int has_arg);
00063 Option(const struct option *longopts, int longopts_index);
00064
00065 char _short_option;
00066 string _long_option;
00067 int _has_arg;
00068 const struct option *_option;
00069 int _longopts_index;
00070 };
00071
00072
00073
00074
00075
00076
00077
00078 class Param {
00079 public:
00080 Param(size_t opt_index, size_t argv_index,
00081 char short_option, char *argument = NULL);
00082
00083 size_t _opt_index;
00084 size_t _argv_index;
00085 char _short_option;
00086 char *_argument;
00087 };
00088
00089
00090 typedef pvector<Option> Options;
00091 Options _options;
00092
00093
00094 typedef pvector<Param> Params;
00095 Params _params;
00096
00097 typedef pvector<char *> Arguments;
00098
00099
00100
00101
00102
00103
00104 Arguments _output_argv;
00105
00106
00107
00108
00109
00110 Arguments _arguments;
00111
00112
00113
00114 bool _return_in_order;
00115 bool _require_order;
00116
00117
00118
00119 bool _allow_one_hyphen_long;
00120
00121
00122
00123 size_t _next_param;
00124
00125
00126
00127
00128 size_t _next_argv_index;
00129 };
00130
00131
00132
00133 static PandaGetopt *pgetopt = NULL;
00134
00135
00136
00137
00138
00139
00140 PandaGetopt::
00141 PandaGetopt(int argc, char *const argv[], const char *optstring,
00142 const struct option *longopts, bool allow_one_hyphen_long) {
00143 assert(optstring != NULL);
00144
00145 _return_in_order = false;
00146 _require_order = false;
00147 _allow_one_hyphen_long = allow_one_hyphen_long;
00148 _next_param = 0;
00149
00150
00151 _options.push_back(Option('?', no_argument));
00152
00153 if (optstring[0] == '-') {
00154
00155
00156
00157 ++optstring;
00158 _return_in_order = true;
00159
00160
00161 _options.push_back(Option('\001', required_argument));
00162
00163 } else if (optstring[0] == '+') {
00164
00165
00166
00167 ++optstring;
00168 _require_order = true;
00169
00170 } else if (getenv("POSIXLY_CORRECT") != NULL) {
00171
00172 _require_order = true;
00173
00174 } else {
00175
00176
00177
00178 }
00179
00180 scan_options(optstring, longopts);
00181 scan_args(argc, argv);
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 void PandaGetopt::
00193 permute(int argc, char **mutable_argv) {
00194 if (!_require_order && !_return_in_order) {
00195
00196 size_t i = 1;
00197 Arguments::const_iterator gi;
00198 for (gi = _output_argv.begin(); gi != _output_argv.end(); ++gi) {
00199 assert((int)i < argc);
00200 mutable_argv[i] = (*gi);
00201 ++i;
00202 }
00203 _next_argv_index = i;
00204 for (gi = _arguments.begin(); gi != _arguments.end(); ++gi) {
00205 assert((int)i < argc);
00206 mutable_argv[i] = (*gi);
00207 ++i;
00208 }
00209 assert((int)i == argc);
00210 }
00211 }
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 int PandaGetopt::
00222 process(int opterr, int *longindex, char *&optarg, int &optind, int &optopt) {
00223 if (_next_param >= _params.size()) {
00224 optind = _next_argv_index;
00225 return EOF;
00226 }
00227
00228 const Param ¶m = _params[_next_param];
00229 ++_next_param;
00230 const Option &option = _options[param._opt_index];
00231
00232 optarg = param._argument;
00233 optind = (int)param._argv_index;
00234 if (longindex != NULL) {
00235 *longindex = option._longopts_index;
00236 }
00237
00238 if (option._option != NULL) {
00239
00240
00241 if (option._option->flag == NULL) {
00242 return option._option->val;
00243 }
00244 *(option._option->flag) = option._option->val;
00245 return 0;
00246 }
00247
00248 if (param._opt_index == 0 && opterr) {
00249
00250 optopt = param._short_option;
00251 cerr << "Illegal option: -" << param._short_option << "\n";
00252 return '?';
00253 }
00254
00255
00256 return param._short_option;
00257 }
00258
00259
00260
00261
00262
00263
00264
00265
00266 size_t PandaGetopt::
00267 find_short_option(char short_option) {
00268 size_t opt_index = 1;
00269 while (opt_index < _options.size()) {
00270 if (_options[opt_index]._short_option == short_option) {
00271 return opt_index;
00272 }
00273 ++opt_index;
00274 }
00275
00276 return 0;
00277 }
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 size_t PandaGetopt::
00289 find_long_option(const string &long_option) {
00290 string search = long_option;
00291 size_t equals = search.find('=');
00292 if (equals != string::npos) {
00293 search = search.substr(0, equals);
00294 }
00295
00296 size_t opt_index = 1;
00297 while (opt_index < _options.size()) {
00298 if (_options[opt_index]._long_option == search) {
00299 return opt_index;
00300 }
00301 ++opt_index;
00302 }
00303
00304 return 0;
00305 }
00306
00307
00308
00309
00310
00311
00312
00313
00314 void PandaGetopt::
00315 scan_options(const char *optstring, const struct option *longopts) {
00316 const char *p = optstring;
00317 while (*p != '\0') {
00318 char short_option = *p;
00319 int has_arg = no_argument;
00320 ++p;
00321 if (*p == ':') {
00322 has_arg = required_argument;
00323 ++p;
00324 if (*p == ':') {
00325 has_arg = optional_argument;
00326 ++p;
00327 }
00328 }
00329
00330 _options.push_back(Option(short_option, has_arg));
00331 }
00332
00333 if (longopts != NULL) {
00334 int longopts_index = 0;
00335 while (longopts[longopts_index].name != NULL) {
00336 _options.push_back(Option(longopts, longopts_index));
00337 ++longopts_index;
00338 }
00339 }
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349 void PandaGetopt::
00350 scan_args(int argc, char *const argv[]) {
00351 size_t ai = 1;
00352 bool end_of_processing = false;
00353
00354 while ((int)ai < argc) {
00355 assert(argv[ai] != NULL);
00356
00357 if (argv[ai][0] != '-' || end_of_processing) {
00358
00359 if (_require_order) {
00360 break;
00361 }
00362 if (_return_in_order) {
00363
00364 _params.push_back(Param(1, ai, '\001', argv[ai]));
00365 _output_argv.push_back(argv[ai]);
00366 } else {
00367
00368 _arguments.push_back(argv[ai]);
00369 }
00370
00371 } else if (strcmp(argv[ai], "--") == 0) {
00372
00373
00374 _output_argv.push_back(argv[ai]);
00375 end_of_processing = true;
00376
00377 } else {
00378
00379
00380 char *option = NULL;
00381 char *argument = NULL;
00382 size_t opt_index = 0;
00383 bool is_long_option = false;
00384 bool has_argument = false;
00385
00386 if (argv[ai][1] == '-') {
00387
00388 option = argv[ai] + 2;
00389 opt_index = find_long_option(option);
00390 is_long_option = true;
00391 } else {
00392
00393
00394 option = argv[ai] + 1;
00395 if (_allow_one_hyphen_long) {
00396
00397 opt_index = find_long_option(option);
00398 if (opt_index != 0) {
00399 is_long_option = true;
00400 }
00401 }
00402 if (!is_long_option) {
00403 opt_index = find_short_option(option[0]);
00404 while (opt_index != 0 &&
00405 _options[opt_index]._has_arg == no_argument &&
00406 option[1] != '\0') {
00407
00408 _params.push_back(Param(opt_index, ai, option[0]));
00409 ++option;
00410 opt_index = find_short_option(option[0]);
00411 }
00412
00413 if (opt_index != 0 && _options[opt_index]._has_arg != no_argument) {
00414 if (option[1] != '\0') {
00415
00416 argument = option + 1;
00417 has_argument = true;
00418 }
00419 }
00420 }
00421 }
00422
00423 if (is_long_option) {
00424 char *equals = strchr(option, '=');
00425 if (equals != NULL) {
00426 argument = equals + 1;
00427 has_argument = true;
00428 }
00429 }
00430
00431 size_t argv_index = ai;
00432
00433 if (opt_index != 0 && _options[opt_index]._has_arg == required_argument &&
00434 !has_argument) {
00435
00436 _output_argv.push_back(argv[ai]);
00437 ++ai;
00438 if ((int)ai < argc) {
00439 argument = argv[ai];
00440 has_argument = true;
00441 }
00442 }
00443
00444 _params.push_back(Param(opt_index, argv_index, option[0], argument));
00445 _output_argv.push_back(argv[ai]);
00446 }
00447 ++ai;
00448 }
00449
00450 _next_argv_index = ai;
00451
00452
00453 while ((int)ai < argc) {
00454 assert(argv[ai] != NULL);
00455 _arguments.push_back(argv[ai]);
00456 ++ai;
00457 }
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467 PandaGetopt::Option::
00468 Option(char short_option, int has_arg) :
00469 _short_option(short_option),
00470 _has_arg(has_arg),
00471 _option(NULL),
00472 _longopts_index(-1)
00473 {
00474 }
00475
00476
00477
00478
00479
00480
00481
00482
00483 PandaGetopt::Option::
00484 Option(const struct option *longopts, int longopts_index) :
00485 _short_option(0),
00486 _long_option(longopts[longopts_index].name),
00487 _has_arg(longopts[longopts_index].has_arg),
00488 _option(&longopts[longopts_index]),
00489 _longopts_index(longopts_index)
00490 {
00491 }
00492
00493
00494
00495
00496
00497
00498 PandaGetopt::Param::
00499 Param(size_t opt_index, size_t argv_index, char short_option, char *argument) :
00500 _opt_index(opt_index),
00501 _argv_index(argv_index),
00502 _short_option(short_option),
00503 _argument(argument)
00504 {
00505 }
00506
00507 int
00508 getopt(int argc, char *const argv[], const char *optstring) {
00509 if (pgetopt == NULL) {
00510 pgetopt = new PandaGetopt(argc, argv, optstring, NULL, false);
00511 pgetopt->permute(argc, (char **)argv);
00512 }
00513 return pgetopt->process(opterr, NULL, optarg, optind, optopt);
00514 }
00515
00516 int
00517 getopt_long(int argc, char *const argv[], const char *optstring,
00518 const struct option *longopts, int *longindex) {
00519 if (pgetopt == NULL) {
00520 pgetopt = new PandaGetopt(argc, argv, optstring, longopts, false);
00521 pgetopt->permute(argc, (char **)argv);
00522 }
00523 return pgetopt->process(opterr, longindex, optarg, optind, optopt);
00524 }
00525
00526 int
00527 getopt_long_only(int argc, char *const argv[], const char *optstring,
00528 const struct option *longopts, int *longindex) {
00529 if (pgetopt == NULL) {
00530 pgetopt = new PandaGetopt(argc, argv, optstring, longopts, true);
00531 pgetopt->permute(argc, (char **)argv);
00532 }
00533 return pgetopt->process(opterr, longindex, optarg, optind, optopt);
00534 }
00535
00536 #endif // defined(HAVE_GETOPT) && defined(HAVE_GETOPT_LONG_ONLY)