00001
00002
00003 #include "ace/Get_Opt.h"
00004
00005 #if !defined (__ACE_INLINE__)
00006 #include "ace/Get_Opt.inl"
00007 #endif
00008
00009 #include "ace/ACE.h"
00010 #include "ace/Log_Msg.h"
00011 #include "ace/SString.h"
00012 #include "ace/OS_Memory.h"
00013 #include "ace/OS_NS_string.h"
00014 #include "ace/OS_NS_ctype.h"
00015 #include "ace/OS_NS_stdlib.h"
00016
00017 ACE_RCSID (ace,
00018 Get_Opt,
00019 "$Id: Get_Opt.cpp 79134 2007-07-31 18:23:50Z johnnyw $")
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00091
00092 ACE_ALLOC_HOOK_DEFINE(ACE_Get_Opt)
00093
00094 ACE_Get_Opt::ACE_Get_Opt (int argc,
00095 ACE_TCHAR **argv,
00096 const ACE_TCHAR *optstring,
00097 int skip,
00098 int report_errors,
00099 int ordering,
00100 int long_only)
00101 : argc_ (argc),
00102 argv_ (argv),
00103 optind (skip),
00104 opterr (report_errors),
00105 optarg (0),
00106 optstring_ (0),
00107 long_only_ (long_only),
00108 has_colon_ (0),
00109 last_option_ (0),
00110 nextchar_ (0),
00111 optopt_ (0),
00112 ordering_ (ordering),
00113 nonopt_start_ (optind),
00114 nonopt_end_ (optind),
00115 long_option_ (0)
00116 {
00117 ACE_TRACE ("ACE_Get_Opt::ACE_Get_Opt");
00118
00119 ACE_NEW (this->optstring_, ACE_TString (optstring));
00120 ACE_NEW (this->last_option_, ACE_TString (ACE_TEXT ("")));
00121
00122
00123
00124 #if defined (ACE_WIN32)
00125 const ACE_TCHAR *env_check = ACE_TEXT ("POSIXLY_CORRECT");
00126 #else
00127 const char *env_check = "POSIXLY_CORRECT";
00128 #endif
00129 if (ACE_OS::getenv (env_check) != 0)
00130 this->ordering_ = REQUIRE_ORDER;
00131
00132
00133
00134
00135
00136
00137
00138 int done = 0;
00139 int offset = 0;
00140 while (!done)
00141 {
00142 switch (optstring[offset++])
00143 {
00144 case '+':
00145 this->ordering_ = REQUIRE_ORDER;
00146 break;
00147 case '-':
00148 this->ordering_ = RETURN_IN_ORDER;
00149 break;
00150 case ':':
00151 this->has_colon_ = 1;
00152 break;
00153 default:
00154
00155 done = 1;
00156 break;
00157 }
00158 }
00159 }
00160
00161 ACE_Get_Opt::~ACE_Get_Opt (void)
00162 {
00163 ACE_TRACE ("ACE_Get_Opt::~ACE_Get_Opt");
00164
00165 size_t i = 0;
00166 size_t size = this->long_opts_.size ();
00167 ACE_Get_Opt_Long_Option *option = 0;
00168 for (i = 0; i < size; ++i)
00169 {
00170 int retval = this->long_opts_.get (option, i);
00171 if (retval != 0)
00172 {
00173
00174 retval = 0;
00175 continue;
00176 }
00177 if (option)
00178 {
00179 delete option;
00180 option = 0;
00181 }
00182 }
00183 delete this->optstring_;
00184 delete this->last_option_;
00185 }
00186
00187 int
00188 ACE_Get_Opt::nextchar_i (void)
00189 {
00190 ACE_TRACE ("ACE_Get_Opt::nextchar_i");
00191
00192 if (this->ordering_ == PERMUTE_ARGS)
00193 if (this->permute () == EOF)
00194 return EOF;
00195
00196
00197 if (this->optind >= this->argc_)
00198 {
00199
00200 this->nextchar_ = 0;
00201 return EOF;
00202 }
00203 else if (*(this->nextchar_ = this->argv_[this->optind]) != '-'
00204 || this->nextchar_[1] == '\0')
00205 {
00206
00207
00208 if (this->ordering_ == REQUIRE_ORDER
00209 || this->ordering_ == PERMUTE_ARGS)
00210
00211 return EOF;
00212
00213
00214 this->optarg = this->argv_[this->optind++];
00215 this->nextchar_ = 0;
00216 return 1;
00217 }
00218 else if (this->nextchar_[1] != 0
00219 && *++this->nextchar_ == '-'
00220 && this->nextchar_[1] == 0)
00221 {
00222
00223 ++this->optind;
00224 this->nextchar_ = 0;
00225 return EOF;
00226 }
00227
00228
00229 if (*this->nextchar_ == '-' && this->long_opts_.size () != 0)
00230 this->nextchar_++;
00231
00232 return 0;
00233 }
00234
00235 int
00236 ACE_Get_Opt::long_option_i (void)
00237 {
00238 ACE_TRACE ("ACE_Get_Opt::long_option_i");
00239
00240 ACE_Get_Opt_Long_Option *p;
00241 ACE_TCHAR *s = this->nextchar_;
00242 int hits = 0;
00243 int exact = 0;
00244 ACE_Get_Opt_Long_Option *pfound = 0;
00245 int indfound = 0;
00246
00247
00248
00249 while (*s && *s != '=')
00250 s++;
00251
00252 size_t len = s - this->nextchar_;
00253
00254 this->last_option (ACE_TString (this->nextchar_, len));
00255
00256 size_t size = this->long_opts_.size ();
00257 u_int option_index = 0;
00258 for (option_index = 0; option_index < size ; option_index++)
00259 {
00260 p = this->long_opts_[option_index];
00261 ACE_ASSERT (p);
00262
00263 if (!ACE_OS::strncmp (p->name_, this->nextchar_, len))
00264 {
00265
00266 pfound = p;
00267 indfound = option_index;
00268 hits += 1;
00269 if (len == ACE_OS::strlen(p->name_))
00270 {
00271
00272 exact = 1;
00273 break;
00274 }
00275 }
00276 }
00277
00278 if ((hits > 1) && !exact)
00279 {
00280
00281
00282 if (this->opterr)
00283 ACE_ERROR ((LM_ERROR,
00284 ACE_TEXT ("%s: option `%s' is ambiguous\n"),
00285 this->argv_[0], this->argv_[this->optind]));
00286 this->nextchar_ = 0;
00287 this->optind++;
00288 return '?';
00289 }
00290
00291 if (pfound != 0)
00292 {
00293
00294 option_index = indfound;
00295 this->optind++;
00296 if (*s)
00297 {
00298
00299
00300 if (pfound->has_arg_ != NO_ARG)
00301
00302 this->optarg = ++s;
00303 else
00304 {
00305
00306
00307 if (this->opterr)
00308 ACE_ERROR
00309 ((LM_ERROR,
00310 ACE_TEXT ("%s: long option `--%s' doesn't allow ")
00311 ACE_TEXT ("an argument\n"),
00312 this->argv_[0], pfound->name_));
00313
00314
00315 }
00316 }
00317 else if (pfound->has_arg_ == ARG_REQUIRED)
00318 {
00319
00320
00321
00322 if (this->optind < this->argc_)
00323
00324 this->optarg = this->argv_[this->optind++];
00325 else
00326 {
00327
00328 if (this->opterr)
00329 ACE_ERROR ((LM_ERROR,
00330 ACE_TEXT ("%s: long option '--%s' requires ")
00331 ACE_TEXT ("an argument\n"),
00332 this->argv_[0], pfound->name_));
00333 this->nextchar_ = 0;
00334 this->optopt_ = pfound->val_;
00335 return this->has_colon_ ? ':' : '?';
00336 }
00337 }
00338 this->nextchar_ = 0;
00339 this->long_option_ = pfound;
00340
00341
00342 this->optopt_ = pfound->val_;
00343 return pfound->val_;
00344 }
00345 if (!this->long_only_ || this->argv_[this->optind][1] == '-'
00346 || this->optstring_->find (*this->nextchar_) == ACE_TString::npos)
00347 {
00348
00349
00350
00351
00352 if (this->opterr)
00353 ACE_ERROR ((LM_ERROR,
00354 ACE_TEXT ("%s: illegal long option '--%s'\n"),
00355 this->argv_[0], this->nextchar_));
00356 this->nextchar_ = 0;
00357 this->optind++;
00358 return '?';
00359 }
00360 return this->short_option_i ();
00361 }
00362
00363 int
00364 ACE_Get_Opt::short_option_i (void)
00365 {
00366 ACE_TRACE ("ACE_Get_Opt::short_option_i");
00367
00368
00369 ACE_TCHAR opt = *this->nextchar_++;
00370
00371 this->last_option (opt);
00372
00373 ACE_TCHAR *oli = 0;
00374 oli =
00375 const_cast<ACE_TCHAR*> (ACE_OS::strchr (this->optstring_->c_str (), opt));
00376
00377
00378 if (*this->nextchar_ == '\0')
00379 ++this->optind;
00380
00381 if (oli == 0 || opt == ':')
00382 {
00383 if (this->opterr)
00384 ACE_ERROR ((LM_ERROR,
00385 ACE_TEXT ("%s: illegal short option -- %c\n"),
00386 this->argv_[0], opt));
00387 return '?';
00388 }
00389 if (opt == 'W' && oli[1] == ';')
00390 {
00391 if (this->nextchar_[0] == 0)
00392 this->nextchar_ = this->argv_[this->optind];
00393 return long_option_i ();
00394 }
00395 this->optopt_ = oli[0];
00396 if (oli[1] == ':')
00397 {
00398 if (oli[2] == ':')
00399 {
00400
00401
00402
00403 if (*this->nextchar_ != '\0')
00404 {
00405 this->optarg = this->nextchar_;
00406 this->optind++;
00407 }
00408 else
00409 this->optarg = 0;
00410 this->nextchar_ = 0;
00411 }
00412 else
00413 {
00414
00415 if (*this->nextchar_ != '\0')
00416 {
00417
00418 this->optarg = this->nextchar_;
00419 this->optind++;
00420 }
00421 else if (this->optind == this->argc_)
00422 {
00423
00424 if (this->opterr)
00425 ACE_ERROR ((LM_ERROR,
00426 ACE_TEXT ("%s: short option requires ")
00427 ACE_TEXT ("an argument -- %c\n"),
00428 this->argv_[0], opt));
00429 opt = this->has_colon_ ? ':' : '?';
00430 }
00431 else
00432
00433 this->optarg = this->argv_[this->optind++];
00434 this->nextchar_ = 0;
00435 }
00436 }
00437 return opt;
00438 }
00439
00440 int
00441 ACE_Get_Opt::operator () (void)
00442 {
00443 ACE_TRACE ("ACE_Get_Opt_Long::operator");
00444
00445
00446 this->optarg = 0;
00447 this->long_option_ = 0;
00448
00449 if (this->argv_ == 0)
00450 {
00451
00452 this->optind = 0;
00453 return -1;
00454 }
00455
00456
00457
00458 if (this->nextchar_ == 0 || *this->nextchar_ == '\0')
00459 {
00460 int retval = this->nextchar_i ();
00461 if (retval != 0)
00462 return retval;
00463 }
00464
00465 if (((this->argv_[this->optind][0] == '-')
00466 && (this->argv_[this->optind][1] == '-')) || this->long_only_)
00467 return this->long_option_i ();
00468
00469 return this->short_option_i ();
00470 }
00471
00472 int
00473 ACE_Get_Opt::long_option (const ACE_TCHAR *name,
00474 OPTION_ARG_MODE has_arg)
00475 {
00476 ACE_TRACE ("ACE_Get_Opt::long_option (const ACE_TCHAR *name, OPTION_ARG_MODE has_arg)");
00477 return this->long_option (name, 0, has_arg);
00478 }
00479
00480 int
00481 ACE_Get_Opt::long_option (const ACE_TCHAR *name,
00482 int short_option,
00483 OPTION_ARG_MODE has_arg)
00484 {
00485 ACE_TRACE ("ACE_Get_Opt::long_option (const ACE_TCHAR *name, int short_option, OPTION_ARG_MODE has_arg)");
00486
00487
00488
00489
00490
00491
00492 if (ACE_OS::ace_isalnum (short_option) != 0)
00493 {
00494
00495
00496 ACE_TCHAR *s = 0;
00497 if ((s = const_cast<ACE_TCHAR*> (
00498 ACE_OS::strchr (this->optstring_->c_str (),
00499 short_option))) != 0)
00500 {
00501
00502 if (s[1] == ':')
00503 {
00504 if (s[2] == ':')
00505 {
00506 if (has_arg != ARG_OPTIONAL)
00507 {
00508 if (this->opterr)
00509 ACE_ERROR
00510 ((LM_ERROR,
00511 ACE_TEXT ("Existing short option '%c' takes ")
00512 ACE_TEXT ("optional argument; adding %s ")
00513 ACE_TEXT ("requires ARG_OPTIONAL\n"),
00514 short_option, name));
00515 return -1;
00516 }
00517 }
00518 else
00519 if (has_arg != ARG_REQUIRED)
00520 {
00521 if (this->opterr)
00522 ACE_ERROR
00523 ((LM_ERROR,
00524 ACE_TEXT ("Existing short option '%c' requires ")
00525 ACE_TEXT ("an argument; adding %s ")
00526 ACE_TEXT ("requires ARG_REQUIRED\n"),
00527 short_option, name));
00528 return -1;
00529 }
00530 }
00531 else if (has_arg != NO_ARG)
00532 {
00533 if (this->opterr)
00534 ACE_ERROR
00535 ((LM_ERROR,
00536 ACE_TEXT ("Existing short option '%c' does not ")
00537 ACE_TEXT ("accept an argument; adding %s ")
00538 ACE_TEXT ("requires NO_ARG\n"),
00539 short_option, name));
00540 return -1;
00541 }
00542 }
00543 else
00544 {
00545
00546 *this->optstring_ += (ACE_TCHAR) short_option;
00547 if (has_arg == ARG_REQUIRED)
00548 *this->optstring_ += ACE_TEXT (":");
00549 else if (has_arg == ARG_OPTIONAL)
00550 *this->optstring_ += ACE_TEXT ("::");
00551 }
00552 }
00553
00554 ACE_Get_Opt_Long_Option *option =
00555 new ACE_Get_Opt_Long_Option (name, has_arg, short_option);
00556
00557 if (!option)
00558 return -1;
00559
00560
00561 size_t size = this->long_opts_.size ();
00562 if (this->long_opts_.size (size + 1) != 0
00563 || this->long_opts_.set (option, size) != 0)
00564 {
00565 delete option;
00566 ACE_ERROR_RETURN
00567 ((LM_ERROR, ACE_TEXT ("Could not add long option to array.\n")),
00568 -1);
00569 }
00570 return 0;
00571 }
00572
00573 const ACE_TCHAR*
00574 ACE_Get_Opt::long_option (void) const
00575 {
00576 ACE_TRACE ("ACE_Get_Opt::long_option (void)");
00577 if (this->long_option_)
00578 return this->long_option_->name_;
00579 return 0;
00580 }
00581
00582 const ACE_TCHAR*
00583 ACE_Get_Opt::last_option (void) const
00584 {
00585 return this->last_option_->c_str ();
00586 }
00587
00588 void
00589 ACE_Get_Opt::last_option (const ACE_TString &last_option)
00590 {
00591 *this->last_option_ = last_option;
00592 }
00593
00594 void
00595 ACE_Get_Opt::dump (void) const
00596 {
00597 #if defined (ACE_HAS_DUMP)
00598 ACE_TRACE ("ACE_Get_Opt::dump");
00599
00600 ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00601 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")
00602 ACE_TEXT ("opstring_ = %s\n")
00603 ACE_TEXT ("long_only_ = %d\n")
00604 ACE_TEXT ("has_colon_ = %d\n")
00605 ACE_TEXT ("last_option_ = %s\n")
00606 ACE_TEXT ("nextchar_ = %s\n")
00607 ACE_TEXT ("optopt_ = %c\n")
00608 ACE_TEXT ("ordering_ = %d\n"),
00609 this->optstring_->c_str (),
00610 this->long_only_,
00611 this->has_colon_,
00612 this->last_option_->c_str (),
00613 this->nextchar_,
00614 this->optopt_,
00615 this->ordering_));
00616
00617
00618 size_t size = this->long_opts_.size ();
00619 for (u_int i = 0; i < size ; ++i)
00620 {
00621 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")
00622 ACE_TEXT ("long_option name_ = %s\n")
00623 ACE_TEXT ("has_arg_ = %d\n")
00624 ACE_TEXT ("val_ = %d\n"),
00625 this->long_opts_[i]->name_,
00626 this->long_opts_[i]->has_arg_,
00627 this->long_opts_[i]->val_));
00628 }
00629 ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00630 #endif
00631 }
00632
00633 void
00634 ACE_Get_Opt::permute_args (void)
00635 {
00636 ACE_TRACE ("ACE_Get_Opt::permute_args");
00637
00638 u_long cyclelen, i, j, ncycle, nnonopts, nopts;
00639 u_long opt_end = this->optind;
00640 int cstart, pos = 0;
00641 ACE_TCHAR *swap = 0;
00642
00643 nnonopts = this->nonopt_end_ - this->nonopt_start_;
00644 nopts = opt_end - this->nonopt_end_;
00645 ncycle = ACE::gcd (nnonopts, nopts);
00646 cyclelen = (opt_end - this->nonopt_start_) / ncycle;
00647
00648 this->optind = this->optind - nnonopts;
00649
00650 for (i = 0; i < ncycle; i++)
00651 {
00652 cstart = this->nonopt_end_ + i;
00653 pos = cstart;
00654 for (j = 0; j < cyclelen; j++)
00655 {
00656 if (pos >= this->nonopt_end_)
00657 pos -= nnonopts;
00658 else
00659 pos += nopts;
00660 swap = this->argv_[pos];
00661
00662 ((ACE_TCHAR **)this->argv_)[pos] = argv_[cstart];
00663
00664 ((ACE_TCHAR **)this->argv_)[cstart] = swap;
00665 }
00666 }
00667 }
00668
00669 int
00670 ACE_Get_Opt::permute (void)
00671 {
00672 ACE_TRACE ("ACE_Get_Opt::permute");
00673
00674 if (this->nonopt_start_ != this->nonopt_end_
00675 && this->nonopt_start_ != this->optind)
00676 this->permute_args ();
00677
00678 this->nonopt_start_ = this->optind;
00679
00680
00681 while (this->optind < this->argc_
00682 && (this->argv_[this->optind][0] != '-'
00683 || this->argv_[this->optind][1] == '\0'))
00684 this->optind++;
00685
00686
00687 this->nonopt_end_ = this->optind;
00688
00689 if (this->optind != this->argc_
00690 && ACE_OS::strcmp (this->argv_[this->optind],
00691 ACE_TEXT ("--")) == 0)
00692 {
00693
00694 this->optind++;
00695
00696 if (this->nonopt_start_ != this->nonopt_end_
00697 && this->nonopt_end_ != this->optind)
00698 this->permute_args ();
00699 }
00700
00701 if (this->optind == this->argc_)
00702 {
00703 if (this->nonopt_start_ != this->nonopt_end_)
00704 this->optind = this->nonopt_start_;
00705 return EOF;
00706 }
00707 return 0;
00708 }
00709
00710 const ACE_TCHAR *
00711 ACE_Get_Opt::optstring (void) const
00712 {
00713 return this->optstring_->c_str ();
00714 }
00715
00716 ACE_Get_Opt::ACE_Get_Opt_Long_Option::ACE_Get_Opt_Long_Option (
00717 const ACE_TCHAR *name,
00718 int has_arg,
00719 int val)
00720 : name_ (ACE::strnew (name)),
00721 has_arg_ (has_arg),
00722 val_ (val)
00723 {}
00724
00725 ACE_Get_Opt::ACE_Get_Opt_Long_Option::~ACE_Get_Opt_Long_Option (void)
00726 {
00727 delete [] this->name_;
00728 }
00729
00730 ACE_END_VERSIONED_NAMESPACE_DECL