00001
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
00035 #include "OW_config.h"
00036 #include "OW_CmdLineParser.hpp"
00037 #include "OW_Array.hpp"
00038 #include "OW_ExceptionIds.hpp"
00039 #include "OW_StringBuffer.hpp"
00040 #include "OW_Assertion.hpp"
00041
00042 #include <algorithm>
00043
00044
00045 namespace OW_NAMESPACE
00046 {
00047
00048 OW_DEFINE_EXCEPTION_WITH_ID(CmdLineParser)
00049
00050 namespace
00051 {
00053 struct longOptIs
00054 {
00055 longOptIs(const String& longOpt) : m_longOpt(longOpt) {}
00056
00057 bool operator()(const CmdLineParser::Option& x) const
00058 {
00059 if (x.longopt != 0)
00060 {
00061 return m_longOpt.startsWith(x.longopt);
00062 }
00063 return false;
00064 }
00065
00066 String m_longOpt;
00067 };
00068
00070 struct shortOptIs
00071 {
00072 shortOptIs(char shortOpt) : m_shortOpt(shortOpt) {}
00073
00074 bool operator()(const CmdLineParser::Option& x) const
00075 {
00076 return m_shortOpt == x.shortopt;
00077 }
00078
00079 char m_shortOpt;
00080 };
00081
00082 }
00083
00085 CmdLineParser::CmdLineParser(int argc, char const* const* const argv_, const Option* options, EAllowNonOptionArgsFlag allowNonOptionArgs)
00086 {
00087 OW_ASSERT(argc > 0);
00088 OW_ASSERT(argv_ != 0);
00089 OW_ASSERT(options != 0);
00090 char const* const* argv = argv_;
00091 char const* const* argvEnd = argv + argc;
00092
00093
00094 const Option* optionsEnd(options);
00095 while (optionsEnd->shortopt != '\0' || optionsEnd->longopt != 0)
00096 {
00097 ++optionsEnd;
00098 }
00099
00100
00101 ++argv;
00102 while (argv != argvEnd)
00103 {
00104 OW_ASSERT(*argv != 0);
00105 String arg(*argv);
00106
00107
00108 if ((arg.length() >= 2) && (arg[0] == '-'))
00109 {
00110 const Option* theOpt(0);
00111 bool longOpt = false;
00112 if (arg[1] == '-')
00113 {
00114
00115 longOpt = true;
00116 arg = arg.substring(2);
00117 theOpt = std::find_if (options, optionsEnd, longOptIs(arg));
00118 }
00119 else
00120 {
00121 longOpt = false;
00122 arg = arg.substring(1);
00123 theOpt = std::find_if (options, optionsEnd, shortOptIs(arg[0]));
00124 }
00125
00126 if (theOpt == optionsEnd)
00127 {
00128 OW_THROW_ERR(CmdLineParserException, arg.c_str(), E_INVALID_OPTION);
00129 }
00130
00131 if (theOpt->argtype == E_NO_ARG)
00132 {
00133 m_parsedOptions[theOpt->id];
00134 ++argv;
00135 continue;
00136 }
00137
00138 String val;
00139 if ((theOpt->argtype == E_OPTIONAL_ARG) && (theOpt->defaultValue != 0))
00140 {
00141 val = theOpt->defaultValue;
00142 }
00143
00144 const char* p = ::strchr(arg.c_str(), '=');
00145 if (p)
00146 {
00147
00148 val = String(p+1);
00149 }
00150 else
00151 {
00152
00153 if (longOpt == false && arg.length() > 1)
00154 {
00155 val = arg.substring(1);
00156 }
00157
00158 else if (argv+1 != argvEnd)
00159 {
00160 if (**(argv+1) != '-')
00161 {
00162 val = *(argv+1);
00163 ++argv;
00164 }
00165 }
00166 }
00167
00168
00169 if (theOpt->argtype == E_REQUIRED_ARG && val.empty())
00170 {
00171 OW_THROW_ERR(CmdLineParserException, arg.c_str(), E_MISSING_ARGUMENT);
00172 }
00173
00174 m_parsedOptions[theOpt->id].push_back(val);
00175 }
00176 else
00177 {
00178 if (allowNonOptionArgs == E_NON_OPTION_ARGS_INVALID)
00179 {
00180 OW_THROW_ERR(CmdLineParserException, arg.c_str(), E_INVALID_NON_OPTION_ARG);
00181 }
00182 else
00183 {
00184 m_nonOptionArgs.push_back(arg);
00185 }
00186 }
00187 ++argv;
00188 }
00189 }
00190
00192
00193 String
00194 CmdLineParser::getUsage(const Option* options, unsigned int maxColumns)
00195 {
00196
00197
00198
00199
00200
00201
00202 const unsigned int NUM_OPTION_COLUMNS = 28;
00203 StringBuffer usage("Options:\n");
00204
00205
00206 for (const Option* curOption = options; curOption->shortopt != '\0' || curOption->longopt != 0; ++curOption)
00207 {
00208 StringBuffer curLine;
00209 curLine += " ";
00210 if (curOption->shortopt != '\0')
00211 {
00212 curLine += '-';
00213 curLine += curOption->shortopt;
00214 if (curOption->longopt != 0)
00215 {
00216 curLine += ", ";
00217 }
00218 }
00219 if (curOption->longopt != 0)
00220 {
00221 curLine += "--";
00222 curLine += curOption->longopt;
00223 }
00224
00225 if (curOption->argtype == E_REQUIRED_ARG)
00226 {
00227 curLine += " <arg>";
00228 }
00229 else if (curOption->argtype == E_OPTIONAL_ARG)
00230 {
00231 curLine += " [arg]";
00232 }
00233
00234 size_t bufferlen = (curLine.length() >= NUM_OPTION_COLUMNS-1) ? 1 : (NUM_OPTION_COLUMNS - curLine.length());
00235 for (size_t i = 0; i < bufferlen; ++i)
00236 {
00237 curLine += ' ';
00238 }
00239
00240 if (curOption->description != 0)
00241 {
00242 curLine += curOption->description;
00243 }
00244
00245 if (curOption->defaultValue != 0)
00246 {
00247 curLine += " (default is ";
00248 curLine += curOption->defaultValue;
00249 curLine += ')';
00250 }
00251
00252
00253 while (curLine.length() > maxColumns || curLine.toString().indexOf('\n') != String::npos)
00254 {
00255 String curLineStr(curLine.toString());
00256
00257 size_t newlineIdx = curLineStr.indexOf('\n');
00258
00259
00260 size_t lastSpaceIdx = curLineStr.lastIndexOf(' ', maxColumns);
00261
00262 size_t cutIdx = 0;
00263 size_t nextLineBeginIdx = 0;
00264 if (newlineIdx <= maxColumns)
00265 {
00266 cutIdx = newlineIdx;
00267 nextLineBeginIdx = newlineIdx + 1;
00268 }
00269 else if (lastSpaceIdx > NUM_OPTION_COLUMNS)
00270 {
00271 cutIdx = lastSpaceIdx;
00272 nextLineBeginIdx = lastSpaceIdx + 1;
00273 }
00274 else
00275 {
00276
00277 cutIdx = maxColumns;
00278 nextLineBeginIdx = maxColumns;
00279 }
00280
00281
00282 usage += curLineStr.substring(0, cutIdx);
00283 usage += '\n';
00284
00285
00286 StringBuffer spaces;
00287 for (size_t i = 0; i < NUM_OPTION_COLUMNS; ++i)
00288 {
00289 spaces += ' ';
00290 }
00291 curLine = spaces.releaseString() + curLineStr.substring(nextLineBeginIdx);
00292 }
00293
00294 curLine += '\n';
00295 usage += curLine;
00296 }
00297 return usage.releaseString();
00298 }
00299
00301 String
00302 CmdLineParser::getOptionValue(int id, const char* defaultValue) const
00303 {
00304 optionsMap_t::const_iterator ci = m_parsedOptions.find(id);
00305 if (ci != m_parsedOptions.end() && ci->second.size() > 0)
00306 {
00307
00308 return ci->second[ci->second.size()-1];
00309 }
00310 return defaultValue;
00311 }
00312
00314 String
00315 CmdLineParser::mustGetOptionValue(int id, const char* exceptionMessage) const
00316 {
00317 optionsMap_t::const_iterator ci = m_parsedOptions.find(id);
00318 if (ci != m_parsedOptions.end() && ci->second.size() > 0)
00319 {
00320
00321 return ci->second[ci->second.size()-1];
00322 }
00323 OW_THROW_ERR(CmdLineParserException, exceptionMessage, E_MISSING_OPTION);
00324 }
00325
00327 StringArray
00328 CmdLineParser::getOptionValueList(int id) const
00329 {
00330 StringArray rval;
00331 optionsMap_t::const_iterator ci = m_parsedOptions.find(id);
00332 if (ci != m_parsedOptions.end() && ci->second.size() > 0)
00333 {
00334 rval = ci->second;
00335 }
00336 return rval;
00337 }
00338
00340 StringArray
00341 CmdLineParser::mustGetOptionValueList(int id, const char* exceptionMessage) const
00342 {
00343 optionsMap_t::const_iterator ci = m_parsedOptions.find(id);
00344 if (ci != m_parsedOptions.end() && ci->second.size() > 0)
00345 {
00346 return ci->second;
00347 }
00348 OW_THROW_ERR(CmdLineParserException, exceptionMessage, E_MISSING_OPTION);
00349 }
00350
00352 bool
00353 CmdLineParser::isSet(int id) const
00354 {
00355 return m_parsedOptions.count(id) > 0;
00356 }
00357
00359 size_t
00360 CmdLineParser::getNonOptionCount () const
00361 {
00362 return m_nonOptionArgs.size();
00363 }
00364
00366 String
00367 CmdLineParser::getNonOptionArg(size_t n) const
00368 {
00369 return m_nonOptionArgs[n];
00370 }
00371
00373 StringArray
00374 CmdLineParser::getNonOptionArgs() const
00375 {
00376 return m_nonOptionArgs;
00377 }
00378
00379
00380
00381 }
00382
00383
00384