00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012 #include "biu/OptionParser.hh"
00013 #include <iostream>
00014
00015 namespace biu {
00016
00018
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
00028
00029
00030
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;
00044 if (opt[i].option.size() > maxOName)
00045 maxOName = opt[i].option.size();
00046 }
00047 }
00048
00049
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
00066 nextCutPos = text.find_last_of("\n",lineLength-emptyHeadSize);
00067 if (nextCutPos == text.npos) {
00068 nextCutPos = text.find_last_of(" ",lineLength-emptyHeadSize);
00069 }
00070 if (nextCutPos == text.npos) {
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
00086 void COptionParser::coutUsage() const {
00087 std::cout <<"\n => usage:\t" <<programName ;
00088 OptionMap::size_type i;
00089
00090
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
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) {
00111 std::cout <<" default=\"" <<opt[i].defValue <<"\"";
00112 }
00113 std::cout <<std::endl;
00114 }
00115
00116
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
00122 std::cout <<" => usage:\t" <<programName ;
00123
00124
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 }
00132
00133
00134 bool COptionParser::argExist(std::string option) {
00135 if (mopt.find(option) != mopt.end()) {
00136 return (opt[mopt[option]].exist || !(opt[mopt[option]].defValue.compare(COption::DEF_INIT) == 0));
00137 }
00138 return false;
00139 }
00140
00141
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
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 }
00212
00213
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 }
00260
00261
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++) {
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++) {
00272 if ( help1.compare(argv[optStart[i]]) == 0
00273 || help2.compare(argv[optStart[i]]) == 0)
00274 {
00275 coutUsage();
00276 errorOccured = true;
00277 return;
00278 }
00279 }
00280 for (i=0; i<optStart.size(); i++) {
00281 actOpt = std::string(argv[optStart[i]]);
00282 if (i+1<optStart.size())
00283 last = optStart[i+1];
00284 else
00285 last = argc;
00286 for(j=optStart[i]+1; j<last; j++)
00287 actOpt.append(" "+std::string(argv[j]));
00288 actOptName = actOpt.substr(1,actOpt.find("=",0)-1);
00289 for(j=0; j< opt.size(); j++) {
00290 if (opt[j].option==actOptName)
00291 break;
00292 }
00293 if (j != opt.size()) {
00294 if (opt[j].retType==COption::BOOL) {
00295 if(actOpt.size() > actOptName.size()+1) {
00296 coutError(ERR_WR_USE, actOptName, "is a boolean and no input argument = '"+actOpt+"'");
00297 } else {
00298 opt[j].strValue = "true";
00299 opt[j].exist = true;
00300 }
00301 } else {
00302 if (actOpt.find("=",0) == std::string::npos) {
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)) {
00309 opt[j].strValue = actVal;
00310 opt[j].exist = true;
00311 } else {
00312 coutError(ERR_WR_VAL, actOptName, "in argument '"+actOpt+"'");
00313 }
00314 }
00315 }
00316 } else {
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 }
00327
00328 }