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 "Get_Opt.cpp,v 4.53 2006/04/19 19:13:09 jwillemsen Exp")
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_LIB_TEXT ("")));
00121
00122
00123
00124 #if defined (ACE_WIN32)
00125 const ACE_TCHAR *env_check = ACE_LIB_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_LIB_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_LIB_TEXT ("%s: long option `--%s' doesn't allow ")
00311 ACE_LIB_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_LIB_TEXT ("%s: long option '--%s' requires ")
00331 ACE_LIB_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_LIB_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_LIB_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_LIB_TEXT ("%s: short option requires ")
00427 ACE_LIB_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 defined (_MSC_VER) && (_MSC_VER >= 1300)
00493
00494
00495 if (short_option > 0 &&
00496 short_option < 256 &&
00497 ACE_OS::ace_isalnum (static_cast<char> (short_option)) != 0)
00498 #else
00499 if (ACE_OS::ace_isalnum (short_option) != 0)
00500 #endif
00501 {
00502
00503
00504 ACE_TCHAR *s = 0;
00505 if ((s = const_cast<ACE_TCHAR*> (
00506 ACE_OS::strchr (this->optstring_->c_str (),
00507 short_option))) != 0)
00508 {
00509
00510 if (s[1] == ':')
00511 {
00512 if (s[2] == ':')
00513 {
00514 if (has_arg != ARG_OPTIONAL)
00515 {
00516 if (this->opterr)
00517 ACE_ERROR
00518 ((LM_ERROR,
00519 ACE_LIB_TEXT ("Existing short option '%c' takes ")
00520 ACE_LIB_TEXT ("optional argument; adding %s ")
00521 ACE_LIB_TEXT ("requires ARG_OPTIONAL\n"),
00522 short_option, name));
00523 return -1;
00524 }
00525 }
00526 else
00527 if (has_arg != ARG_REQUIRED)
00528 {
00529 if (this->opterr)
00530 ACE_ERROR
00531 ((LM_ERROR,
00532 ACE_LIB_TEXT ("Existing short option '%c' requires ")
00533 ACE_LIB_TEXT ("an argument; adding %s ")
00534 ACE_LIB_TEXT ("requires ARG_REQUIRED\n"),
00535 short_option, name));
00536 return -1;
00537 }
00538 }
00539 else if (has_arg != NO_ARG)
00540 {
00541 if (this->opterr)
00542 ACE_ERROR
00543 ((LM_ERROR,
00544 ACE_LIB_TEXT ("Existing short option '%c' does not ")
00545 ACE_LIB_TEXT ("accept an argument; adding %s ")
00546 ACE_LIB_TEXT ("requires NO_ARG\n"),
00547 short_option, name));
00548 return -1;
00549 }
00550 }
00551 else
00552 {
00553
00554 *this->optstring_ += (ACE_TCHAR) short_option;
00555 if (has_arg == ARG_REQUIRED)
00556 *this->optstring_ += ACE_LIB_TEXT (":");
00557 else if (has_arg == ARG_OPTIONAL)
00558 *this->optstring_ += ACE_LIB_TEXT ("::");
00559 }
00560 }
00561
00562 ACE_Get_Opt_Long_Option *option =
00563 new ACE_Get_Opt_Long_Option (name, has_arg, short_option);
00564
00565 if (!option)
00566 return -1;
00567
00568
00569 size_t size = this->long_opts_.size ();
00570 if (this->long_opts_.size (size + 1) != 0
00571 || this->long_opts_.set (option, size) != 0)
00572 {
00573 delete option;
00574 ACE_ERROR_RETURN
00575 ((LM_ERROR, ACE_LIB_TEXT ("Could not add long option to array.\n")),
00576 -1);
00577 }
00578 return 0;
00579 }
00580
00581 const ACE_TCHAR*
00582 ACE_Get_Opt::long_option (void) const
00583 {
00584 ACE_TRACE ("ACE_Get_Opt::long_option (void)");
00585 if (this->long_option_)
00586 return this->long_option_->name_;
00587 return 0;
00588 }
00589
00590 const ACE_TCHAR*
00591 ACE_Get_Opt::last_option (void) const
00592 {
00593 return this->last_option_->c_str ();
00594 }
00595
00596 void
00597 ACE_Get_Opt::last_option (const ACE_TString &last_option)
00598 {
00599 *this->last_option_ = last_option;
00600 }
00601
00602 void
00603 ACE_Get_Opt::dump (void) const
00604 {
00605 #if defined (ACE_HAS_DUMP)
00606 ACE_TRACE ("ACE_Get_Opt::dump");
00607
00608 ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00609 ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")
00610 ACE_LIB_TEXT ("opstring_ = %s\n")
00611 ACE_LIB_TEXT ("long_only_ = %d\n")
00612 ACE_LIB_TEXT ("has_colon_ = %d\n")
00613 ACE_LIB_TEXT ("last_option_ = %s\n")
00614 ACE_LIB_TEXT ("nextchar_ = %s\n")
00615 ACE_LIB_TEXT ("optopt_ = %c\n")
00616 ACE_LIB_TEXT ("ordering_ = %d\n"),
00617 this->optstring_->c_str (),
00618 this->long_only_,
00619 this->has_colon_,
00620 this->last_option_->c_str (),
00621 this->nextchar_,
00622 this->optopt_,
00623 this->ordering_));
00624
00625
00626 size_t size = this->long_opts_.size ();
00627 for (u_int i = 0; i < size ; ++i)
00628 {
00629 ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")
00630 ACE_LIB_TEXT ("long_option name_ = %s\n")
00631 ACE_LIB_TEXT ("has_arg_ = %d\n")
00632 ACE_LIB_TEXT ("val_ = %d\n"),
00633 this->long_opts_[i]->name_,
00634 this->long_opts_[i]->has_arg_,
00635 this->long_opts_[i]->val_));
00636 }
00637 ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00638 #endif
00639 }
00640
00641 void
00642 ACE_Get_Opt::permute_args (void)
00643 {
00644 ACE_TRACE ("ACE_Get_Opt::permute_args");
00645
00646 u_long cyclelen, i, j, ncycle, nnonopts, nopts;
00647 u_long opt_end = this->optind;
00648 int cstart, pos = 0;
00649 ACE_TCHAR *swap = 0;
00650
00651 nnonopts = this->nonopt_end_ - this->nonopt_start_;
00652 nopts = opt_end - this->nonopt_end_;
00653 ncycle = ACE::gcd (nnonopts, nopts);
00654 cyclelen = (opt_end - this->nonopt_start_) / ncycle;
00655
00656 this->optind = this->optind - nnonopts;
00657
00658 for (i = 0; i < ncycle; i++)
00659 {
00660 cstart = this->nonopt_end_ + i;
00661 pos = cstart;
00662 for (j = 0; j < cyclelen; j++)
00663 {
00664 if (pos >= this->nonopt_end_)
00665 pos -= nnonopts;
00666 else
00667 pos += nopts;
00668 swap = this->argv_[pos];
00669
00670 ((ACE_TCHAR **)this->argv_)[pos] = argv_[cstart];
00671
00672 ((ACE_TCHAR **)this->argv_)[cstart] = swap;
00673 }
00674 }
00675 }
00676
00677 int
00678 ACE_Get_Opt::permute (void)
00679 {
00680 ACE_TRACE ("ACE_Get_Opt::permute");
00681
00682 if (this->nonopt_start_ != this->nonopt_end_
00683 && this->nonopt_start_ != this->optind)
00684 this->permute_args ();
00685
00686 this->nonopt_start_ = this->optind;
00687
00688
00689 while (this->optind < this->argc_
00690 && (this->argv_[this->optind][0] != '-'
00691 || this->argv_[this->optind][1] == '\0'))
00692 this->optind++;
00693
00694
00695 this->nonopt_end_ = this->optind;
00696
00697 if (this->optind != this->argc_
00698 && ACE_OS::strcmp (this->argv_[this->optind],
00699 ACE_LIB_TEXT ("--")) == 0)
00700 {
00701
00702 this->optind++;
00703
00704 if (this->nonopt_start_ != this->nonopt_end_
00705 && this->nonopt_end_ != this->optind)
00706 this->permute_args ();
00707 }
00708
00709 if (this->optind == this->argc_)
00710 {
00711 if (this->nonopt_start_ != this->nonopt_end_)
00712 this->optind = this->nonopt_start_;
00713 return EOF;
00714 }
00715 return 0;
00716 }
00717
00718 const ACE_TCHAR *
00719 ACE_Get_Opt::optstring (void) const
00720 {
00721 return this->optstring_->c_str ();
00722 }
00723
00724 ACE_Get_Opt::ACE_Get_Opt_Long_Option::ACE_Get_Opt_Long_Option (
00725 const ACE_TCHAR *name,
00726 int has_arg,
00727 int val)
00728 : name_ (ACE::strnew (name)),
00729 has_arg_ (has_arg),
00730 val_ (val)
00731 {}
00732
00733 ACE_Get_Opt::ACE_Get_Opt_Long_Option::~ACE_Get_Opt_Long_Option (void)
00734 {
00735 delete [] this->name_;
00736 }
00737
00738 ACE_END_VERSIONED_NAMESPACE_DECL