# 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: todos@geneura.ugr.es, http://geneura.ugr.es
    00022              Marc.Schoenauer@inria.fr
    00023              mkeijzer@dhi.dk
    00024  */
    00025 //-----------------------------------------------------------------------------
    00026
    00027 #ifdef _MSC_VER
    00028 #pragma warning(disable:4786)
    00029 #endif
    00030
    00031 #include <stdexcept>
    00032 #include <algorithm>
    00033 #include <fstream>
    00034 #include <iomanip>
    00035
    00036 #include <utils/compatibility.h>
    00037
    00038 #include <utils/eoParser.h>
    00039
    00040 using namespace std;
    00041
    00042 void eoWarning(std::string str)
    00043 {
    00044     cout << str << '\n';
    00045 }
    00046
    00047 std::ostream& printSectionHeader(std::ostream& os, std::string section)
    00048 {
    00049     if (section == "")
    00050         section = "General";
    00051
    00052     os << '\n' << setw(10) << "######    " << setw(20) << section << setw(10) << "    ######\n";
    00053     return os;
    00054 }
    00055
    00056 eoParameterLoader::~eoParameterLoader()
    00057 {
    00058     for (unsigned i = 0; i < ownedParams.size(); ++i)
    00059     {
    00060         delete ownedParams[i];
    00061     }
    00062 }
    00063
    00064
    00065 eoParser::eoParser ( unsigned _argc, char **_argv , string _programDescription,
    00066                      string _lFileParamName, char _shortHand) :
    00067     programName(_argv[0]),
    00068     programDescription( _programDescription),
    00069     needHelp(false, "help", "Prints this message", 'h'),
    00070     stopOnUnknownParam(true, "stopOnUnknownParam", "Stop if unkown param entered", '\0')
    00071 {
    00072     // need to process the param file first
    00073     // if we want command-line to have highest priority
    00074     unsigned i;
    00075     for (i = 1; i < _argc; ++i)
    00076     {
    00077         if(_argv[i][0] == '@')
    00078         { // read response file
    00079             char *pts = _argv[i]+1; // yes a char*, sorry :-)
    00080             ifstream ifs (pts);
    00081             ifs.peek(); // check if it exists
    00082             if (!ifs)
    00083             {
    00084                 string msg = string("Could not open response file: ") + pts;
    00085                 throw runtime_error(msg);
    00086             }
    00087             // read  - will be overwritten by command-line
    00088             readFrom(ifs);
    00089             break; // stop reading command line args for '@'
    00090         }
    00091     }
    00092     // now read arguments on command-line
    00093     stringstream stream;
    00094     for (i = 1; i < _argc; ++i)
    00095     {
    00096         stream << _argv[i] << '\n';
    00097     }
    00098     readFrom(stream);
    00099     processParam(needHelp);
    00100     processParam(stopOnUnknownParam);
    00101 }
    00102
    00103
    00104
    00105 eoParam * eoParser::getParamWithLongName(const std::string& _name) const
    00106 {
    00107     typedef std::multimap<std::string, eoParam*> MultiMapType;
    00108     typedef MultiMapType::const_iterator iter;
    00109     std::string search(prefix+_name);
    00110     for(iter p = params.begin(); p != params.end(); ++p)
    00111         if(p->second->longName() == search)
    00112             return p->second;
    00113     return 0;
    00114 }
    00115
    00116
    00117
    00118 void eoParser::processParam(eoParam& param, std::string section)
    00119 {
    00120     // this param enters the parser: add the prefix to the long name
    00121     if (prefix != "")
    00122     {
    00123         param.setLongName(prefix+param.longName());
    00124         section = prefix + section;  // and to section
    00125     }
    00126     doRegisterParam(param); // plainly register it
    00127     params.insert(make_pair(section, &param));
    00128 }
    00129
    00130 void eoParser::doRegisterParam(eoParam& param) const
    00131 {
    00132     if (param.required() && !isItThere(param))
    00133     {
    00134         string msg = "Required parameter: " + param.longName() + " missing";
    00135         messages.push_back(msg);
    00136     }
    00137     pair<bool, string> value = getValue(param);
    00138     if (value.first)
    00139     {
    00140         param.setValue(value.second);
    00141     }
    00142 }
    00143
    00144 pair<bool, string> eoParser::getValue(eoParam& _param) const
    00145 {
    00146     pair<bool, string> result(false, "");
    00147
    00148     if (_param.shortName() != 0)
    00149     {
    00150         map<char, string>::const_iterator it = shortNameMap.find(_param.shortName());
    00151         if (it != shortNameMap.end())
    00152         {
    00153             result.second = it->second;
    00154             result.first = true;
    00155             return result;
    00156         }
    00157     }
    00158     map<string, string>::const_iterator it = longNameMap.find(_param.longName());
    00159     if (it != longNameMap.end())
    00160     {
    00161         result.second = it->second;
    00162         result.first = true;
    00163         return result;
    00164     }
    00165     // else (TODO: check environment, just long names)
    00166     return result;
    00167 }
    00168
    00169 void eoParser::updateParameters() const
    00170 {
    00171  typedef MultiMapType::const_iterator It;
    00172
    00173   for (It p = params.begin(); p != params.end(); ++p)
    00174   {
    00175         doRegisterParam(*p->second);
    00176   }
    00177 }
    00178
    00179 void eoParser::readFrom(istream& is)
    00180 {
    00181     string str;
    00182     // we must avoid processing \section{xxx} if xxx is NOT "Parser"
    00183     bool processing = true;
    00184     while (is >> str)
    00185     {
    00186         if (str.find(string("\\section{"))==0) // found section begin
    00187             processing = (str.find(string("Parser"))<str.size());
    00188
    00189         if (processing)         // right \section (or no \section at all)
    00190         {
    00191             if (str[0] == '#')
    00192             { // skip the rest of the line
    00193                 string tempStr;
    00194                 getline(is, tempStr);
    00195             }
    00196             if (str[0] == '-')
    00197             {
    00198                 if (str.size() < 2)
    00199                 {
    00200                     eoWarning("Missing parameter");
    00201                     needHelp.value() = true;
    00202                     return;
    00203                 }
    00204
    00205                 if (str[1] == '-') // two consecutive dashes
    00206                 {
    00207                     string::iterator equalLocation = find(str.begin() + 2, str.end(), '=');
    00208                     string value;
    00209
    00210                     if (equalLocation == str.end())
    00211                     { // TODO: it should be the next string
    00212                         value = "";
    00213                     }
    00214                     else
    00215                     {
    00216                         value = string(equalLocation + 1, str.end());
    00217                     }
    00218
    00219                     string name(str.begin() + 2, equalLocation);
    00220                     longNameMap[name] = value;
    00221
    00222                 }
    00223                 else // it should be a char
    00224                 {
    00225                     string value = "1"; // flags do not need a special
    00226
    00227                     if (str.size() >= 2)
    00228                     {
    00229                         if (str[2] == '=')
    00230                         {
    00231                             if (str.size() >= 3)
    00232                                 value = string(str.begin() + 3, str.end());
    00233                         }
    00234                         else
    00235                         {
    00236                             value = string(str.begin() + 2, str.end());
    00237                         }
    00238                     }
    00239
    00240                     shortNameMap[str[1]] = value;
    00241                 }
    00242             }
    00243         }
    00244     }
    00245
    00246     updateParameters();
    00247 }
    00248
    00249 void eoParser::printOn(ostream& os) const
    00250 {
    00251     typedef MultiMapType::const_iterator It;
    00252
    00253     It p = params.begin();
    00254
    00255     std::string section = p->first;
    00256
    00257     printSectionHeader(os, section);
    00258     //print every param with its value
    00259     for (; p != params.end(); ++p)
    00260       {
    00261         std::string newSection = p->first;
    00262
    00263         if (newSection != section)
    00264         {
    00265             section = newSection;
    00266             printSectionHeader(os, section);
    00267         }
    00268
    00269         eoParam* param = p->second;
    00270
    00271         if (!isItThere(*param))  // comment out the ones not set by the user
    00272           os << "# ";
    00273
    00274         string str = "--" + param->longName() + "=" + param->getValue();
    00275
    00276         os.setf(ios_base::left, ios_base::adjustfield);
    00277         os << setw(40) << str;
    00278
    00279         os << setw(0) << " # ";
    00280         if (param->shortName())
    00281             os << '-' << param->shortName() << " : ";
    00282         os << param->description();
    00283
    00284         if (param->required())
    00285         {
    00286             os << " REQUIRED ";
    00287         }
    00288
    00289         os  << '\n';
    00290     }
    00291 }
    00292
    00293 void eoParser::printHelp(ostream& os)
    00294 {
    00295     if (needHelp.value() == false && !messages.empty())
    00296     {
    00297         std::copy(messages.begin(), messages.end(), ostream_iterator<string>(os, "\n"));
    00298         messages.clear();
    00299         return;
    00300     }
    00301
    00302     // print program name and description
    00303     os << this->programName <<": "<< programDescription << "\n\n";
    00304
    00305     // print the usage when calling the program from the command line
    00306     os << "Usage: "<< programName<<" [Options]\n";
    00307     // only short usage!
    00308     os << "Options of the form \"-f[=Value]\" or \"--Name[=value]\"" << endl;
    00309
    00310     os << "Where:"<<endl;
    00311
    00312     typedef MultiMapType::const_iterator It;
    00313
    00314     It p = params.begin();
    00315
    00316     std::string section = p->first;
    00317
    00318     printSectionHeader(os, section);
    00319
    00320     //print every param with its value
    00321     for (; p != params.end(); ++p)
    00322     {
    00323         std::string newSection = p->first;
    00324
    00325         if (newSection != section)
    00326         {
    00327             section = newSection;
    00328             printSectionHeader(os, section);
    00329         }
    00330
    00331         if (p->second->shortName())
    00332                 os << "-" << p->second->shortName() << ", ";
    00333
    00334         os << "--" <<p->second->longName() <<":\t"
    00335              << p->second->description() ;
    00336
    00337           os << "\n" << setw(20) << ( (p->second->required())?"Required":"Optional" );
    00338       os <<". By default: "<<p->second->defValue() << '\n';
    00339     } // for p
    00340
    00341     os << "\n@param_file \t defines a file where the parameters are stored\n";
    00342     os << '\n';
    00343
    00344 }
    00345
    00346 bool eoParser::userNeedsHelp(void)
    00347 {
    00348   /*
    00349      check whether there are long or short names entered
    00350      without a corresponding parameter
    00351   */
    00352   // first, check if we want to check that !
    00353   if (stopOnUnknownParam.value())
    00354     {
    00355       for (LongNameMapType::const_iterator lIt = longNameMap.begin(); lIt != longNameMap.end(); ++lIt)
    00356         {
    00357           string entry = lIt->first;
    00358
    00359           MultiMapType::const_iterator it;
    00360
    00361           for (it = params.begin(); it != params.end(); ++it)
    00362             {
    00363               if (entry == it->second->longName())
    00364                 {
    00365                   break;
    00366                 }
    00367             }
    00368
    00369           if (it == params.end())
    00370             {
    00371               string msg = "Unknown parameter: --" + entry + " entered, type -h or --help to see available parameters";
    00372               messages.push_back(msg);
    00373             }
    00374         }
    00375
    00376       for (ShortNameMapType::const_iterator sIt = shortNameMap.begin(); sIt != shortNameMap.end(); ++sIt)
    00377         {
    00378           char entry = sIt->first;
    00379
    00380           MultiMapType::const_iterator it;
    00381
    00382           for (it = params.begin(); it != params.end(); ++it)
    00383             {
    00384               if (entry == it->second->shortName())
    00385                 {
    00386                   break;
    00387                 }
    00388             }
    00389
    00390           if (it == params.end())
    00391             {
    00392               string entryString(1, entry);
    00393               string msg = "Unknown parameter: -" + entryString + " entered, type -h or --help to see available parameters";
    00394               messages.push_back(msg);
    00395             }
    00396         }
    00397     }
    00398   return needHelp.value() || !messages.empty();
    00399 }
    00400
    00402 ostream & operator<<(ostream & _os, const eoParamParamType & _rate)
    00403 {
    00404   _rate.printOn(_os);
    00405   return _os;
    00406 }
    00407
    00408 istream & operator>>(istream & _is,  eoParamParamType & _rate)
    00409 {
    00410   _rate.readFrom(_is);
    00411   return _is;
    00412 }
    00413