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