Generated on Mon Jun 23 16:24:56 2008 for BIU-1.7.0 by doxygen 1.5.1

src/biu/OptionParser.cc

Go to the documentation of this file.
00001 // OptionParser.cpp: Implementierung der Klasse COptionParser.
00002 /*
00003 
00004     <author>    Martin Mann                 </author>
00005     <created>   9.10.2005                   </created>
00006 
00007     <info>                                  </info>
00008 */
00009 //
00011 
00012 #include "biu/OptionParser.hh"
00013 #include <iostream>
00014 
00015 namespace biu {
00016     
00018 // statics aus COption
00020 
00021 std::string COption::DEF_INIT = "§$%&/()=";
00022 std::vector<std::string> COption::TYPE_NAME = COption::initTypeNames();
00023 int COptionParser::OUTPUT_LINE_LENGTH = 80;
00024 
00026 // Konstruktion
00028 
00029 
00030 // Konstruktor
00031 COptionParser::COptionParser(OptionMap _options, int argc, char** argv, std::string infoText) 
00032 :   opt(_options), 
00033     programName(std::string(argv[0])), 
00034     infoText(infoText), 
00035     errorOccured(false), 
00036     maxOName(0) {
00037     if (programName.find_last_of("/\\")!=std::string::npos)
00038         programName = programName.substr(programName.find_last_of("/\\")+1);
00039     parseOpt(argc, argv);
00040 
00041 
00042     for (OptionMap::size_type i=0; i<opt.size(); i++) {
00043         mopt[opt[i].option] = i;                // merke mit zuordnung fuer "direkten" zugriff
00044         if (opt[i].option.size() > maxOName)    // merke laenge des laengesten optionsnamens
00045             maxOName = opt[i].option.size();
00046     }
00047 } // construction()
00048 
00049 // zeigt ob Probleme beim Parsen vorliegen
00050 bool COptionParser::noErrors() {
00051     return !errorOccured;
00052 }
00053 
00054 
00055 void COptionParser::coutLineBreaking(std::string text, std::ostream &os,const int emptyHeadSize,const int lineLength) const {
00056 
00057     std::string line = "", emptyHead = std::string(emptyHeadSize, ' ');
00058 
00059     size_t nextCutPos = std::max(lineLength-emptyHeadSize,0);
00060 
00061     bool firstOut = true, cutted = false;
00062 
00063     while ((int)text.size() >  (lineLength-emptyHeadSize)) {
00064         cutted = false;
00065             // suche zeilenumbruch zum trennen
00066         nextCutPos = text.find_last_of("\n",lineLength-emptyHeadSize);
00067         if (nextCutPos == text.npos) {  // nixs -> suche leerzeichen zum trennen
00068             nextCutPos = text.find_last_of(" ",lineLength-emptyHeadSize);
00069         }
00070         if (nextCutPos == text.npos) {  // notwendige worttrennung
00071             nextCutPos = lineLength-emptyHeadSize;
00072             cutted = true;
00073         }
00074         line += text.substr(0, nextCutPos);
00075         text = text.substr(nextCutPos+(cutted?0:1));
00076         os <<line <<std::endl;
00077         firstOut = false;
00078         line = emptyHead;
00079     }
00080     if (text.size() > 0)
00081         os <<(firstOut?"":emptyHead) <<text<<std::endl;
00082 
00083 }
00084 
00085 // zeigt Parameter an
00086 void COptionParser::coutUsage() const {
00087     std::cout <<"\n => usage:\t" <<programName ;
00088     OptionMap::size_type i;
00089 
00090     // ausgabe von nicht optionalen parametern
00091     for (i=0; i<opt.size(); i++) {
00092         if (opt[i].optional)
00093             continue;
00094         std::cout <<" -"<<opt[i].option <<(opt[i].retType==COption::BOOL?"":"=...");
00095     }
00096     std::cout <<" [...optional parameters]\n\n => complete parameterlist:\n";
00097     std::cout <<std::endl;
00098 
00099     int maxName = maxOName + 7, j=0, preStrLength = maxName +2;
00100     std::string pInfo = "", emptyPreStr = std::string(preStrLength,' ');
00101 
00102     // komplette parameterliste
00103     for (i=0; i<opt.size(); i++) {
00104         pInfo = std::string(opt[i].optional?"  [-":"   -") + opt[i].option + std::string(opt[i].retType==COption::BOOL?"":"=..");
00105         for (j = pInfo.size(); j<maxName; j++)
00106             pInfo += " ";
00107         std::cout <<pInfo <<(opt[i].optional?"] ":"  ");
00108         coutLineBreaking(opt[i].description, std::cout, preStrLength, OUTPUT_LINE_LENGTH);
00109         std::cout <<emptyPreStr<<"type=" <<COption::TYPE_NAME[opt[i].retType];
00110         if (opt[i].defValue.compare(COption::DEF_INIT) != 0) { // dann defaultwert vorhanden
00111             std::cout <<"  default=\"" <<opt[i].defValue <<"\"";
00112         }
00113         std::cout <<std::endl;
00114     }
00115 
00116     // zusaetzliche informationen
00117     std::cout <<"\n\n => informations:\n\n";
00118     coutLineBreaking(infoText, std::cout, 0, OUTPUT_LINE_LENGTH);
00119     std::cout <<"\n"<<std::endl;
00120 
00121     // nochmal usage
00122     std::cout <<" => usage:\t" <<programName ;
00123 
00124     // ausgabe von nicht optionalen parametern
00125     for (i=0; i<opt.size(); i++) {
00126         if (opt[i].optional)
00127             continue;
00128         std::cout <<" -"<<opt[i].option <<(opt[i].retType==COption::BOOL?"":"=...");
00129     }
00130     std::cout <<" [...optional parameters]"<<std::endl;
00131 } // coutUsage()
00132 
00133 // zeigt ob der entsprechende Parameter angegeben wurde
00134 bool COptionParser::argExist(std::string option) {
00135     if (mopt.find(option) != mopt.end()) {// dann existiert die option
00136         return (opt[mopt[option]].exist || !(opt[mopt[option]].defValue.compare(COption::DEF_INIT) == 0)); // dann auch angegeben
00137     }
00138     return false;
00139 }
00140 
00141 // Parse-Funktionen
00142 
00143 std::string COptionParser::getStrVal(std::string arg) {
00144     if (argExist(arg)) {
00145         return opt[mopt[arg]].strValue;
00146     } else {
00147         return "";
00148     }
00149 }
00150 char COptionParser::getCharVal(std::string arg) {
00151     if (argExist(arg)) {
00152         return opt[mopt[arg]].strValue[0];
00153     } else {
00154         return ' ';
00155     }
00156 }
00157 int COptionParser::getIntVal(std::string arg) {
00158     if (argExist(arg)) {
00159         int ret;
00160         std::istringstream is;
00161         is.str(opt[mopt[arg]].strValue);
00162         is >> ret;
00163         return ret;
00164     } else {
00165         return 0;
00166     }
00167 }
00168 float COptionParser::getFloatVal(std::string arg) {
00169     if (argExist(arg)) {
00170         float ret;
00171         std::istringstream is;
00172         is.str(opt[mopt[arg]].strValue);
00173         is >> ret;
00174         return ret;
00175     } else {
00176         return 0.0;
00177     }
00178 }
00179 double COptionParser::getDoubleVal(std::string arg) {
00180     if (argExist(arg)) {
00181         double ret;
00182         std::istringstream is;
00183         is.str(opt[mopt[arg]].strValue);
00184         is >> ret;
00185         return ret;
00186     } else {
00187         return 0.0;
00188     }
00189 }
00190 bool COptionParser::getBoolVal(std::string arg) {
00191         return argExist(arg);
00192 }
00193 
00194 
00195 
00196 
00197 
00198 
00199 // liefert formatierte Fehlerausgabe
00200 void COptionParser::coutError(int error, std::string optionName, std::string errormsg) {
00201     errorOccured = true;
00202     std::cout <<"\n\tERROR : ";
00203     switch (error) {
00204         case ERR_NO_OPT : std::cout <<"unknown option : "; break;
00205         case ERR_WR_USE : std::cout <<"wrong usage : "; break;
00206         case ERR_WR_VAL : std::cout <<"wrong argument type : "; break;
00207         case ERR_NO_ARG : std::cout <<"needed argument not given : "; break;
00208         default : std::cout <<" errorcode = " <<error <<" : "; break;
00209     }
00210     std::cout <<"'" <<optionName <<"' " <<errormsg <<std::endl<<std::endl;
00211 } // coutError()
00212 
00213 // prueft, ob Parameter parsebar
00214 bool COptionParser::isCastable(std::string val, int type) const {
00215     std::istringstream ss;
00216     ss.str(val);
00217     std::string dump;
00218 
00219     switch (type) {
00220         case COption::STRING :  return true;
00221         case COption::CHAR  :   char ac;
00222                                         if (!(ss >> ac)) {
00223                                             return false;
00224                                         } else {
00225                                             if ((ss >> dump) && dump.size() > 0 && dump.find_first_not_of(" \t")!=std::string::npos)
00226                                                 return false;
00227                                             else
00228                                                 return true;
00229                                         }
00230         case COption::INT       :   int ai;
00231                                         if (!(ss >> ai)) {
00232                                             return false;
00233                                         } else {
00234                                             if ((ss >> dump) && dump.size() > 0 && dump.find_first_not_of(" \t")!=std::string::npos)
00235                                                 return false;
00236                                             else
00237                                                 return true;
00238                                         }
00239         case COption::DOUBLE    :   double ad;
00240                                         if (!(ss >> ad)) {
00241                                             return false;
00242                                         } else {
00243                                             if ((ss >> dump) && dump.size() > 0 && dump.find_first_not_of(" \t")!=std::string::npos)
00244                                                 return false;
00245                                             else
00246                                                 return true;
00247                                         }
00248         case COption::FLOAT :   float af;
00249                                         if (!(ss >> af)) {
00250                                             return false;
00251                                         } else {
00252                                             if ((ss >> dump) && dump.size() > 0 && dump.find_first_not_of(" \t")!=std::string::npos)
00253                                                 return false;
00254                                             else
00255                                                 return true;
00256                                         }
00257         default : return false;
00258     }
00259 } // isCastable()
00260 
00261 // parst Parameter
00262 void COptionParser::parseOpt(int argc, char** argv) {
00263     std::vector<int> optStart;
00264     OptionMap::size_type i,j,last;
00265     std::string actOpt, actOptName, actVal;
00266     for (int k=1; k < argc; k++) { // merke mir alle potentiellen optionsstarts
00267         if (argv[k][0] == '-')
00268         optStart.push_back(k);
00269     }
00270     std::string help1 = "-help", help2 = "--help";
00271     for (i=0; i<optStart.size(); i++) { // check for 'help' parameter
00272         if (     help1.compare(argv[optStart[i]]) == 0 
00273                 || help2.compare(argv[optStart[i]]) == 0) 
00274         {
00275             coutUsage();
00276             errorOccured = true; // for program abort if wanted
00277             return;
00278         }
00279     }
00280     for (i=0; i<optStart.size(); i++) { // gehe optionen durch
00281         actOpt = std::string(argv[optStart[i]]);
00282         if (i+1<optStart.size())  // entweder argumente bis zur naechsten option
00283             last = optStart[i+1];
00284         else  // oder alle nachfolgenden argumente bis zum ende zusammenfuegen
00285             last = argc;
00286         for(j=optStart[i]+1; j<last; j++)  // erzeuge komplette option
00287             actOpt.append(" "+std::string(argv[j]));
00288         actOptName = actOpt.substr(1,actOpt.find("=",0)-1); // optionsname zum pruefen
00289         for(j=0; j< opt.size(); j++) { // suche eintrag in opt
00290             if (opt[j].option==actOptName)
00291                 break;
00292         }
00293         if (j != opt.size()) {  // dann option tatsaechlich verfuegbar
00294             if (opt[j].retType==COption::BOOL) { // extrabehandlund der booleans
00295                 if(actOpt.size() > actOptName.size()+1) { // dann falsche benutzung
00296                     coutError(ERR_WR_USE, actOptName, "is a boolean and no input argument = '"+actOpt+"'");
00297                 } else { // merken
00298                     opt[j].strValue = "true";
00299                     opt[j].exist = true;
00300                 }
00301             } else {
00302                 if (actOpt.find("=",0) == std::string::npos) { // dann keine zuweisung obwohl kein bool
00303                     coutError(ERR_WR_USE, actOptName, "is an input argument. use '='");
00304                 } else {
00305                     actVal = actOpt.substr(actOptName.size()+2);
00306                     if (actVal.size() == 0) {
00307                         coutError(ERR_WR_VAL, actOptName, "is given with empty input");
00308                     } else if (isCastable(actVal, opt[j].retType)) {  // wenn typecast moeglich
00309                         opt[j].strValue = actVal;                   // dann speichere
00310                         opt[j].exist = true;
00311                     } else {  // fehler da typecast nicht moeglich
00312                         coutError(ERR_WR_VAL, actOptName, "in argument '"+actOpt+"'");
00313                     }
00314                 }
00315             }
00316         } else { // fehlermeldung
00317             coutError(ERR_NO_OPT,actOptName, "in argument '"+actOpt+"'");
00318             break;
00319         }
00320     }
00321     for (i=0; i<opt.size(); i++) {
00322         if(!(opt[i].optional) && !(opt[i].exist)) {
00323             coutError(ERR_NO_ARG,opt[i].option,"check usage");
00324         }
00325     }
00326 } // parseoption()
00327 
00328 } //namespace biu