cgma
|
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