EvolvingObjects
|
00001 // -*- mode: c++; c-indent-level: 4; c++-member-init-indent: 8; comment-column: 35; -*- 00002 00003 //----------------------------------------------------------------------------- 00004 // eoParser.cpp 00005 // (c) Marc Schoenauer, Maarten Keijzer and GeNeura Team, 2000 00006 /* 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Lesser General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License along with this library; if not, write to the Free Software 00019 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00020 00021 Contact: http://eodev.sourceforge.net 00022 Authors: 00023 todos@geneura.ugr.es, http://geneura.ugr.es 00024 Marc.Schoenauer@polytechnique.fr 00025 mkeijzer@dhi.dk 00026 Johann DrĂ©o <johann.dreo@thalesgroup.com> 00027 */ 00028 //----------------------------------------------------------------------------- 00029 00030 #ifdef _MSC_VER 00031 #pragma warning(disable:4786) 00032 #endif 00033 00034 #include <stdexcept> 00035 #include <algorithm> 00036 #include <fstream> 00037 #include <iomanip> 00038 #include <cctype> 00039 00040 #include <utils/compatibility.h> 00041 #include <utils/eoParser.h> 00042 #include <utils/eoLogger.h> 00043 00044 00045 using namespace std; 00046 00047 std::ostream& printSectionHeader(std::ostream& os, std::string section) 00048 { 00049 if (section == "") 00050 section = "General"; 00051 00052 // convert each character to upper case 00053 std::transform( section.begin(), section.end(), section.begin(), ::toupper); 00054 00055 // the formating with setfill would not permits to add this extra space as 00056 // one more call to stream operator, thus it is inserted here 00057 section += ' '; 00058 00059 // pretty print so as to print the section, followed by as many # as 00060 // necessary to fill the line until 80 characters 00061 os << std::endl 00062 << "### " 00063 << std::left 00064 << std::setfill('#') 00065 << std::setw(80) // TODO do not hard code the width of the line 00066 << section 00067 << std::endl; 00068 return os; 00069 } 00070 00071 eoParameterLoader::~eoParameterLoader() 00072 { 00073 for (unsigned i = 0; i < ownedParams.size(); ++i) 00074 { 00075 delete ownedParams[i]; 00076 } 00077 } 00078 00079 eoParser::eoParser ( unsigned _argc, char **_argv , string _programDescription, 00080 string _lFileParamName, char _shortHand) : 00081 programName(_argv[0]), 00082 programDescription( _programDescription), 00083 needHelpMessage( false ), 00084 needHelp(false, "help", "Prints this message", 'h'), 00085 stopOnUnknownParam(true, "stopOnUnknownParam", "Stop if unkown param entered", '\0') 00086 { 00087 // need to process the param file first 00088 // if we want command-line to have highest priority 00089 unsigned i; 00090 for (i = 1; i < _argc; ++i) 00091 { 00092 if(_argv[i][0] == '@') 00093 { // read response file 00094 char *pts = _argv[i]+1; // yes a char*, sorry :-) 00095 ifstream ifs (pts); 00096 ifs.peek(); // check if it exists 00097 if (!ifs) 00098 { 00099 string msg = string("Could not open response file: ") + pts; 00100 throw runtime_error(msg); 00101 } 00102 // read - will be overwritten by command-line 00103 readFrom(ifs); 00104 break; // stop reading command line args for '@' 00105 } 00106 } 00107 // now read arguments on command-line 00108 stringstream stream; 00109 for (i = 1; i < _argc; ++i) 00110 { 00111 stream << _argv[i] << '\n'; 00112 } 00113 readFrom(stream); 00114 processParam(needHelp); 00115 processParam(stopOnUnknownParam); 00116 } 00117 00118 00119 std::string eoParser::get( const std::string & name) const 00120 { 00121 return getParamWithLongName( name )->getValue(); 00122 } 00123 00124 00125 eoParam * eoParser::getParamWithLongName(const std::string& _name) const 00126 { 00127 typedef std::multimap<std::string, eoParam*> MultiMapType; 00128 typedef MultiMapType::const_iterator iter; 00129 std::string search(prefix+_name); 00130 for(iter p = params.begin(); p != params.end(); ++p) 00131 if(p->second->longName() == search) 00132 return p->second; 00133 return 0; 00134 } 00135 00136 eoParam * eoParser::getParam(const std::string& _name) const 00137 { 00138 eoParam * p = getParamWithLongName( _name ); 00139 if( p == NULL ) { 00140 throw eoMissingParamException(_name ); 00141 } else { 00142 return p; 00143 } 00144 } 00145 00146 void eoParser::processParam(eoParam& param, std::string section) 00147 { 00148 // this param enters the parser: add the prefix to the long name 00149 if (prefix != "") 00150 { 00151 param.setLongName(prefix+param.longName()); 00152 section = prefix + section; // and to section 00153 } 00154 doRegisterParam(param); // plainly register it 00155 params.insert(make_pair(section, ¶m)); 00156 } 00157 00158 void eoParser::doRegisterParam(eoParam& param) 00159 { 00160 if (param.required() && !isItThere(param)) 00161 { 00162 string msg = "Required parameter: " + param.longName() + " missing"; 00163 needHelpMessage = true; 00164 messages.push_back(msg); 00165 } 00166 pair<bool, string> value = getValue(param); 00167 if (value.first) 00168 { 00169 param.setValue(value.second); 00170 } 00171 } 00172 00173 pair<bool, string> eoParser::getValue(eoParam& _param) const 00174 { 00175 pair<bool, string> result(false, ""); 00176 00177 if (_param.shortName() != 0) 00178 { 00179 map<char, string>::const_iterator it = shortNameMap.find(_param.shortName()); 00180 if (it != shortNameMap.end()) 00181 { 00182 result.second = it->second; 00183 result.first = true; 00184 return result; 00185 } 00186 } 00187 map<string, string>::const_iterator it = longNameMap.find(_param.longName()); 00188 if (it != longNameMap.end()) 00189 { 00190 result.second = it->second; 00191 result.first = true; 00192 return result; 00193 } 00195 return result; 00196 } 00197 00198 void eoParser::updateParameters() 00199 { 00200 typedef MultiMapType::const_iterator It; 00201 00202 for (It p = params.begin(); p != params.end(); ++p) 00203 { 00204 doRegisterParam(*p->second); 00205 } 00206 } 00207 00208 void eoParser::readFrom(istream& is) 00209 { 00210 string str; 00211 // we must avoid processing \section{xxx} if xxx is NOT "Parser" 00212 bool processing = true; 00213 while (is >> str) 00214 { 00215 if (str.find(string("\\section{"))==0) // found section begin 00216 processing = (str.find(string("Parser"))<str.size()); 00217 00218 if (processing) // right \section (or no \section at all) 00219 { 00220 if (str[0] == '#') 00221 { // skip the rest of the line 00222 string tempStr; 00223 getline(is, tempStr); 00224 } 00225 if (str[0] == '-') 00226 { 00227 if (str.size() < 2) 00228 { 00229 eo::log << eo::warnings << "Missing parameter" << std::endl; 00230 needHelp.value() = true; 00231 return; 00232 } 00233 00234 if (str[1] == '-') // two consecutive dashes 00235 { 00236 string::iterator equalLocation = find(str.begin() + 2, str.end(), '='); 00237 string value; 00238 00239 if (equalLocation == str.end()) 00240 { 00241 value = ""; 00242 } 00243 else 00244 { 00245 value = string(equalLocation + 1, str.end()); 00246 } 00247 00248 string name(str.begin() + 2, equalLocation); 00249 longNameMap[name] = value; 00250 } 00251 else // it should be a char 00252 { 00253 string value = "1"; // flags do not need a special 00254 00255 if (str.size() >= 2) 00256 { 00257 if (str[2] == '=') 00258 { 00259 if (str.size() >= 3) 00260 value = string(str.begin() + 3, str.end()); 00261 } 00262 else 00263 { 00264 value = string(str.begin() + 2, str.end()); 00265 } 00266 } 00267 00268 shortNameMap[str[1]] = value; 00269 } 00270 } 00271 } 00272 } 00273 00274 updateParameters(); 00275 } 00276 00277 void eoParser::printOn(ostream& os) const 00278 { 00279 typedef MultiMapType::const_iterator It; 00280 00281 It p = params.begin(); 00282 00283 std::string section = p->first; 00284 00285 printSectionHeader(os, section); 00286 //print every param with its value 00287 for (; p != params.end(); ++p) 00288 { 00289 std::string newSection = p->first; 00290 00291 if (newSection != section) 00292 { 00293 section = newSection; 00294 printSectionHeader(os, section); 00295 } 00296 00297 eoParam* param = p->second; 00298 00299 if (!isItThere(*param)) // comment out the ones not set by the user 00300 os << "# "; 00301 00302 string str = "--" + param->longName() + "=" + param->getValue(); 00303 00304 os.setf(ios_base::left, ios_base::adjustfield); 00305 os << setfill(' ') << setw(40) << str; 00306 00307 os << setw(0) << " # "; 00308 if (param->shortName()) 00309 os << '-' << param->shortName() << " : "; 00310 os << param->description(); 00311 00312 if (param->required()) 00313 { 00314 os << " REQUIRED "; 00315 } 00316 00317 os << '\n'; 00318 } 00319 } 00320 00321 void eoParser::printHelp(ostream& os) 00322 { 00323 if (needHelp.value() == false && !messages.empty()) 00324 { 00325 std::copy(messages.begin(), messages.end(), ostream_iterator<string>(os, "\n")); 00326 messages.clear(); 00327 return; 00328 } 00329 00330 // print program name and description 00331 os << this->programName <<": "<< programDescription << "\n\n"; 00332 00333 // print the usage when calling the program from the command line 00334 os << "Usage: "<< programName<<" [Options]\n"; 00335 // only short usage! 00336 os << "Options of the form \"-f[=Value]\" or \"--Name[=value]\"" << endl; 00337 00338 os << "Where:"<<endl; 00339 00340 typedef MultiMapType::const_iterator It; 00341 00342 It p = params.begin(); 00343 00344 std::string section = p->first; 00345 00346 printSectionHeader(os, section); 00347 00348 //print every param with its value 00349 for (; p != params.end(); ++p) 00350 { 00351 std::string newSection = p->first; 00352 00353 if (newSection != section) 00354 { 00355 section = newSection; 00356 printSectionHeader(os, section); 00357 } 00358 00359 if (p->second->shortName()) 00360 os << "-" << p->second->shortName() << ", "; 00361 00362 os << "--" <<p->second->longName() <<" :\t" 00363 << p->second->description() ; 00364 00365 os << " (" << ( (p->second->required())?"required":"optional" ); 00366 os <<", default: "<< p->second->defValue() << ')' << std::endl; 00367 } // for p 00368 00369 os << "\n@param_file \t defines a file where the parameters are stored\n"; 00370 os << '\n'; 00371 00372 } 00373 00374 bool eoParser::userNeedsHelp(void) 00375 { 00376 /* 00377 check whether there are long or short names entered 00378 without a corresponding parameter 00379 */ 00380 // first, check if we want to check that ! 00381 if (stopOnUnknownParam.value()) 00382 { 00383 // search for unknown long names 00384 for (LongNameMapType::const_iterator lIt = longNameMap.begin(); lIt != longNameMap.end(); ++lIt) 00385 { 00386 string entry = lIt->first; 00387 00388 MultiMapType::const_iterator it; 00389 00390 for (it = params.begin(); it != params.end(); ++it) 00391 { 00392 if (entry == it->second->longName()) 00393 { 00394 break; 00395 } 00396 } 00397 00398 if (it == params.end()) 00399 { 00400 string msg = "Unknown parameter: --" + entry + " entered"; 00401 needHelpMessage = true; 00402 messages.push_back(msg); 00403 } 00404 } // for lIt 00405 00406 // search for unknown short names 00407 for (ShortNameMapType::const_iterator sIt = shortNameMap.begin(); sIt != shortNameMap.end(); ++sIt) 00408 { 00409 char entry = sIt->first; 00410 00411 MultiMapType::const_iterator it; 00412 00413 for (it = params.begin(); it != params.end(); ++it) 00414 { 00415 if (entry == it->second->shortName()) 00416 { 00417 break; 00418 } 00419 } 00420 00421 if (it == params.end()) 00422 { 00423 string entryString(1, entry); 00424 string msg = "Unknown parameter: -" + entryString + " entered"; 00425 needHelpMessage = true; 00426 messages.push_back(msg); 00427 } 00428 } // for sIt 00429 00430 if( needHelpMessage ) { 00431 string msg = "Use -h or --help to get help about available parameters"; 00432 messages.push_back( msg ); 00433 } 00434 00435 } // if stopOnUnknownParam 00436 00437 return needHelp.value() || !messages.empty(); 00438 } 00439 00441 ostream & operator<<(ostream & _os, const eoParamParamType & _rate) 00442 { 00443 _rate.printOn(_os); 00444 return _os; 00445 } 00446 00447 istream & operator>>(istream & _is, eoParamParamType & _rate) 00448 { 00449 _rate.readFrom(_is); 00450 return _is; 00451 }