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