00001 #pragma ident "$Id: CommandOptionParser.cpp 2390 2010-04-14 17:34:03Z architest $"
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00051 #include <cstring>
00052 #include "CommandOptionParser.hpp"
00053
00054 #include "StringUtils.hpp"
00055
00056 using namespace std;
00057 using namespace gpstk::StringUtils;
00058
00059 #ifdef _MSC_VER
00060 #if ( _MSC_VER < 1600 )
00061 #define min(VAL1, VAL2) _cpp_min(VAL1, VAL2)
00062 #define max(VAL1, VAL2) _cpp_max(VAL1, VAL2)
00063 #endif
00064 #endif
00065
00066 namespace gpstk
00067 {
00068
00069
00070 void
00071 CommandOptionParser::parseOptions(int argc,
00072 char* argv[])
00073 {
00074
00075 CommandOptionMap com;
00076
00077
00078 unsigned int order = 0;
00079
00080
00081
00082 progName = string(argv[0]);
00083 string::size_type slashPos = progName.rfind('/');
00084 if (slashPos != string::npos)
00085 progName = progName.substr(slashPos + 1);
00086
00087 string shortOptString;
00088 struct option* optArray = NULL;
00089 unsigned long optArraySize = 0;
00090
00091 CommandOption *trailing = NULL;
00092
00093
00094 CommandOptionVec::size_type index;
00095 for(index = 0; index < optionVec.size(); index++)
00096 {
00097
00098 switch (optionVec[index]->optType)
00099 {
00100 case CommandOption::trailingType:
00101 if (trailing)
00102 errorStrings.push_back("More than one trailing argument"
00103 " object used (programming error");
00104 else
00105 trailing = optionVec[index];
00106 break;
00107 case CommandOption::stdType:
00108 if (optionVec[index]->shortOpt != 0)
00109 {
00110 shortOptString += optionVec[index]->toGetoptShortOption();
00111 com[string(1,optionVec[index]->shortOpt)] = optionVec[index];
00112 }
00113
00114
00115 if (!optionVec[index]->longOpt.empty())
00116 {
00117 resizeOptionArray(optArray, optArraySize);
00118 optArray[optArraySize - 1] =
00119 optionVec[index]->toGetoptLongOption();
00120 com[optionVec[index]->longOpt] = optionVec[index];
00121 }
00122
00123
00124
00125 if (optionVec[index]->required)
00126 hasRequiredArguments = true;
00127 else
00128 hasOptionalArguments = true;
00129 break;
00130 default:
00131
00132 break;
00133 }
00134 }
00135
00136
00137 resizeOptionArray(optArray, optArraySize);
00138 struct option lastOption = {0,0,0,0};
00139 optArray[optArraySize - 1] = lastOption;
00140
00141
00142 shortOptString.insert((string::size_type)0, (string::size_type)1, '+');
00143
00144 int cha;
00145 int optionIndex;
00146
00147
00148 opterr = 0;
00149
00150 while (optind < argc)
00151 {
00152 if ((cha = getopt_long(argc, argv, shortOptString.c_str(),
00153 optArray, &optionIndex)) == -1)
00154 {
00155 if (!trailing)
00156 errorStrings.push_back("Excess arguments");
00157 break;
00158 }
00159
00160 order++;
00161
00162
00163
00164
00165
00166
00167 if ((cha == '?') || (cha == ':'))
00168 {
00169
00170
00171 string errorArg;
00172
00173 if (optopt != 0)
00174 errorArg = string(1, (char)optopt);
00175
00176 else
00177 errorArg = argv[optind - 1];
00178 errorStrings.push_back(string("Option error: " + errorArg));
00179 }
00180
00181 else
00182 {
00183 string thisOption;
00184
00185
00186 if (cha != 0)
00187 thisOption = string(1,(char)cha);
00188 else
00189 thisOption = string(optArray[optionIndex].name);
00190
00191
00192 map<string, CommandOption*>::iterator itr = com.find(thisOption);
00193
00194 if (itr != com.end())
00195 {
00196 CommandOption* pickedOption = (*itr).second;
00197
00198 if (optarg)
00199 {
00200 if (pickedOption->optFlag == CommandOption::noArgument)
00201 {
00202 errorStrings.push_back(string("Option ") +
00203 thisOption +
00204 string(" has an argument but it shouldn't."));
00205 }
00206
00207
00208 else if (pickedOption->optFlag == CommandOption::hasArgument)
00209 {
00210 pickedOption->value.push_back(string(optarg));
00211 pickedOption->count++;
00212 pickedOption->order = order;
00213 }
00214
00215 }
00216
00217 else
00218 {
00219 if (pickedOption->optFlag == CommandOption::hasArgument)
00220 {
00221 errorStrings.push_back(string("Option ") +
00222 thisOption +
00223 string(" has no argument when it should."));
00224 }
00225
00226 else if (pickedOption->optFlag == CommandOption::noArgument)
00227 {
00228 pickedOption->count++;
00229 pickedOption->order = order;
00230 }
00231 }
00232 }
00233 else
00234 {
00235 errorStrings.push_back("Unknown option error");
00236 }
00237 }
00238 }
00239
00240
00241 if (optind < argc)
00242 {
00243 if (trailing)
00244 {
00245 int i;
00246 for(i = optind; i < argc; i++)
00247 {
00248 trailing->value.push_back(string(argv[i]));
00249 trailing->count++;
00250 }
00251 }
00252
00253 }
00254
00255 for(index = 0; index < optionVec.size(); index++)
00256 {
00257 string retVal = optionVec[index]->checkArguments();
00258 if (!retVal.empty())
00259 errorStrings.push_back(retVal);
00260
00261
00262 if (optionVec[index]->maxCount != 0)
00263 {
00264 if (optionVec[index]->count > optionVec[index]->maxCount)
00265 {
00266 string errstr("Option ");
00267 errstr += optionVec[index]->getOptionString();
00268 errstr += string(" appeared more times than allowed.");
00269 errorStrings.push_back(errstr);
00270 }
00271 }
00272 }
00273
00274 delete [] optArray;
00275 }
00276
00277 ostream& CommandOptionParser::dumpErrors(ostream& out)
00278 {
00279 vector<string>::size_type index;
00280 for(index = 0; index < errorStrings.size(); index++)
00281 out << errorStrings[index] << endl;
00282 return out;
00283 }
00284
00285
00286
00287 ostream& CommandOptionParser::displayUsage(ostream& out, bool doPretty)
00288 {
00289 CommandOptionVec::size_type index;
00290 CommandOption *trailing = NULL;
00291
00292 char *colch = getenv("COLUMNS");
00293 int columns = 80;
00294 unsigned maxlen = 0;
00295 if (colch)
00296 {
00297 string colStr(colch);
00298 columns = asInt(colStr);
00299 }
00300
00301
00302 for (index = 0; index < optionVec.size(); index++)
00303 {
00304 if (optionVec[index]->optType == CommandOption::trailingType)
00305 trailing = optionVec[index];
00306 else if (optionVec[index]->optType == CommandOption::stdType)
00307 maxlen = std::max(maxlen,
00308 unsigned(optionVec[index]->getFullOptionString().length()));
00309 }
00310
00311 out << "Usage: " << progName;
00312 if (hasRequiredArguments || hasOptionalArguments)
00313 out << " [OPTION] ...";
00314 if (trailing)
00315 out << " " << trailing->description;
00316 out << endl
00317 << (doPretty ? prettyPrint(text,"\n","","",columns) : text);
00318
00319
00320
00321
00322 for(int required = 1; required >= 0; required--)
00323 {
00324 if (required==1 && hasRequiredArguments)
00325 out << endl << "Required arguments:" << endl;
00326 else if (required==0 && hasOptionalArguments)
00327 out << endl << "Optional arguments:" << endl;
00328
00329 for(index = 0; index < optionVec.size(); index++)
00330 {
00331 if ((optionVec[index]->required == (required==1)) &&
00332 (optionVec[index]->optType == CommandOption::stdType))
00333 {
00334 string optstr(optionVec[index]->getFullOptionString());
00335 string desc(optionVec[index]->description);
00336 string indent(maxlen, ' ');
00337
00338 if(doPretty) {
00339 leftJustify(optstr, maxlen);
00340 prettyPrint(desc, "\n", indent, optstr, columns);
00341 }
00342 out << desc;
00343 if(!doPretty) out << endl;
00344 }
00345 }
00346 }
00347
00348 return out;
00349 }
00350
00351
00352 void CommandOptionParser::resizeOptionArray(struct option *&oldArray,
00353 unsigned long& oldSize)
00354 {
00355 struct option* newArray = new struct option[1 + oldSize];
00356 std::memcpy(newArray, oldArray, oldSize * sizeof(struct option));
00357 delete [] oldArray;
00358 oldArray = newArray;
00359 newArray = NULL;
00360 oldSize += 1;
00361 }
00362
00363 }