EvolvingObjects
eoParser.cpp
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, &param));
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 }
 All Classes Namespaces Files Functions Variables Typedefs Friends