cgma
GetLongOpt.cpp
Go to the documentation of this file.
00001 /* S Manoharan. Advanced Computer Research Institute. Lyon. France */
00002 
00003 #include "GetLongOpt.hpp"
00004 #include "CubitMessage.hpp"
00005 #include "CubitUtil.hpp"
00006 #include "CubitFileUtil.hpp"
00007 
00008 const CubitString GetLongOpt::TOGGLE_ON = "True";
00009 const CubitString GetLongOpt::TOGGLE_OFF = "False";
00010 
00011 GetLongOpt::GetLongOpt(const char optmark)
00012 {
00013    optmarker = optmark;
00014 }
00015 
00016 GetLongOpt::~GetLongOpt()
00017 {
00018 }
00019 
00020 int GetLongOpt::enroll(const CubitString &opt, const OptType t,
00021 const CubitString &desc, const CubitString &val)
00022 {
00023    Cell c;
00024    c.option = opt;
00025    c.type = t;
00026    c.description = !desc.is_empty() ? desc : "no description available";
00027    c.value = val;
00028    c.wasSet = 0;
00029 
00030    this->mTable.insert(std::make_pair(c.option, c));
00031 
00032    return 1;
00033 }
00034 
00035 CubitString
00036 GetLongOpt::retrieve(const CubitString &opt) const
00037 {
00038   std::map<CubitString, Cell>::const_iterator iter;
00039   iter = mTable.find(CubitString(opt));
00040   if(iter == mTable.end())
00041   {
00042     PRINT_ERROR("GetLongOpt::retrieve - unenrolled option %c%s\n", optmarker, opt.c_str() );
00043     return 0;
00044   }
00045   return iter->second.value.c_str();
00046 }
00047 
00048 int GetLongOpt::parse(const std::vector<CubitString>& args, const CubitString &p)
00049 {
00050   int this_optind = 1;
00051   int argc = args.size();
00052   
00053   CubitString pname = p;
00054   if(pname.is_empty())
00055   {
00056     CubitString dirpart;
00057     CubitFileUtil::split_path(args[0], dirpart, pname);
00058   }
00059 
00060   if ( argc-- <= 1 )
00061   {
00062     return this_optind;
00063   }
00064 
00065   size_t i = 1;
00066   
00067   while ( argc >= 1 )
00068   {
00069     CubitString token = args[i++].c_str();
00070     CubitString next_token = i<args.size() ? args[i] : "";
00071     --argc;
00072     
00073     if ( token.get_at(0) != optmarker || token.get_at(1) == optmarker )
00074       break;    /* end of options */
00075     
00076     ++this_optind;
00077 
00078     size_t token_index = token.find("=", 1);
00079     CubitString token_value = token.substr(token_index != CubitString::npos ? token_index : CubitString::npos);
00080     token = token.substr(1, token_index);
00081     size_t token_len = token.length();
00082 
00083     Table::iterator t;
00084     enum { NoMatch, ExactMatch, PartialMatch } matchStatus = NoMatch;
00085     Table::iterator pc = mTable.end();  // pointer to the partially-matched cell
00086     bool toggle = true; // toggle state for partial match cell
00087 
00088     for ( t = mTable.begin(); t != mTable.end(); t++ )
00089     {
00090       bool match = strncmp(token.c_str(), t->second.option.c_str(), token_len) == 0;
00091       bool no = false;
00092 
00093       if(!match && t->second.type == Toggle &&
00094          token.length() > 2 && token.get_at(0) == 'n' && token.get_at(1) == 'o')
00095       {
00096         match = strncmp(token.c_str() + 2, t->second.option.c_str(), token_len-2) == 0;
00097         no = true;
00098       }
00099 
00100       if (match)
00101       {
00102         if ( t->second.option.length() == (no ? token_len-2 : token_len) )
00103         {
00104             /* an exact match found */
00105           if (t->second.type == Toggle && token_value.is_empty())
00106             token_value = no ? GetLongOpt::TOGGLE_OFF : GetLongOpt::TOGGLE_ON;
00107             
00108           int stat = setcell(t->second, token_value, next_token, pname);
00109           if ( stat == -1 ) return -1;
00110           else if ( stat == 1 )
00111           {
00112             i++; --argc; ++this_optind;
00113           }
00114           matchStatus = ExactMatch;
00115           break;
00116         }
00117         else
00118         {
00119             /* partial match found */
00120           matchStatus = PartialMatch;
00121           pc = t;
00122           toggle = !no;
00123         }
00124       } /* end if */
00125     } /* end for */
00126     
00127     if ( matchStatus == PartialMatch )
00128     {
00129       if (pc->second.type == Toggle && token_value.is_empty() )
00130         token_value = toggle ? GetLongOpt::TOGGLE_ON : GetLongOpt::TOGGLE_OFF;
00131         
00132       int stat = setcell(pc->second, token_value, next_token, pname);
00133       if ( stat == -1 ) return -1;
00134       else if ( stat == 1 ) 
00135       {
00136         ++i; --argc; ++this_optind;
00137       }
00138     }
00139     else if ( matchStatus == NoMatch )
00140     {
00141       PRINT_ERROR("%s: unrecognized option %c%s\n",
00142                   pname.c_str(), optmarker, token.c_str() );
00143       return -1;        /* no match */
00144     }
00145     
00146   } /* end while */
00147   
00148   return this_optind;
00149 }
00150 
00151 int GetLongOpt::parse(const CubitString& opt_string, const CubitString& p)
00152 {
00153   std::vector<CubitString> args;
00154   opt_string.tokenize(' ', args);
00155   return parse(args, p);
00156 }
00157 
00158 /* ----------------------------------------------------------------
00159 GetLongOpt::setcell returns
00160    -1   if there was an error
00161     0   if the nexttoken was not consumed
00162     1   if the nexttoken was consumed
00163 ------------------------------------------------------------------- */
00164 int
00165 GetLongOpt::setcell(Cell &c, const CubitString& valtoken, const CubitString& nexttoken,
00166                     const CubitString& name)
00167 {
00168    switch ( c.type ) {
00169     case GetLongOpt::Toggle :
00170       if ( valtoken != GetLongOpt::TOGGLE_ON && valtoken != GetLongOpt::TOGGLE_OFF ) {
00171         PRINT_ERROR("%s: unsolicited value for flag %c[no]%s\n",
00172           name.c_str(), optmarker, c.option.c_str() );
00173         return -1;  /* unsolicited value specification */
00174       }
00175       c.value = valtoken;
00176       return 0;
00177       
00178     case GetLongOpt::Valueless :
00179       if ( valtoken.get_at(0) == '=' ) {
00180         PRINT_ERROR("%s: unsolicited value for flag %c%s\n",
00181           name.c_str(), optmarker,c.option.c_str() );
00182         return -1;  /* unsolicited value specification */
00183       }
00184       if (!c.wasSet)
00185       {
00186         c.value = GetLongOpt::TOGGLE_ON;
00187         c.wasSet = 1;
00188       }
00189       return 0;
00190     case GetLongOpt::OptionalValue :
00191       if ( valtoken.get_at(0) == '=' ) {
00192         c.value = valtoken.substr(1);
00193       }
00194       else {
00195         if ( !nexttoken.is_empty() && nexttoken.get_at(0) != optmarker ) {
00196           c.value = nexttoken;
00197           return 1;
00198           }
00199       }
00200 
00201       // explicit return here, just to make sure another if-case isn't 
00202       // put in which falls through to the next case (in the absence of
00203       // a break statement)
00204       return 0;
00205     case GetLongOpt::MandatoryValue :
00206       int return_val;
00207       if ( valtoken.get_at(0) == '=' ) {
00208         c.value = valtoken.substr(1);
00209         return_val = 0;
00210       }
00211       else {
00212         if ( !nexttoken.is_empty() && nexttoken.get_at(0) != optmarker ) {
00213           c.value = nexttoken;
00214           return_val = 1;
00215       }
00216       else {
00217         PRINT_ERROR("%s: mandatory value for %c%s\n",
00218           name.c_str(), optmarker, c.option.c_str() );
00219         return_val = -1;    /* mandatory value not specified */
00220         }
00221       }
00222       return return_val;
00223     default :
00224       break;
00225    }
00226    return -1;
00227 }
00228 
00229 void 
00230 GetLongOpt::options(std::ostream &outfile) const
00231 {
00232   Table::const_iterator iter;
00233   for(iter = mTable.begin(); iter != mTable.end(); ++iter)
00234   {
00235     const Cell& t = iter->second;
00236     outfile << "\t" << optmarker;
00237     if ( t.type == GetLongOpt::Toggle )
00238       outfile << "[no]";
00239     outfile << t.option.str();
00240     if ( t.type == GetLongOpt::MandatoryValue )
00241       outfile << " <$val>";
00242     else if ( t.type == GetLongOpt::OptionalValue )
00243       outfile << " [$val]";
00244     outfile << " (" << t.description.str() << ")\n";
00245   }
00246 }
00247 
00248 void
00249 GetLongOpt::usage( std::ostream &outfile, const CubitString& p, const CubitString& ustring) const
00250 {
00251    outfile << "usage: " << p.str() << " " << ustring.str() << "\n";
00252    options(outfile);
00253 }
00254 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines