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 

Generated on Thu Oct 19 05:06:36 2006 for EO by  doxygen 1.3.9.1