73 const std::string& iProgramVersion,
74 const std::string& iPositionalArguments):
75 programName_(iProgramName),
76 programVersion_(iProgramVersion),
77 positionals_(iPositionalArguments),
92 bool allPositionals =
false;
94 for (TArguments::size_type i = 0; i < iArguments.size(); ++i)
96 std::string arg = iArguments[i];
99 if (arg[0] ==
'-' && !allPositionals)
101 if (arg.length() > 1)
105 if (arg.length() > 2)
108 result &= parseLong(iArguments, i);
113 allPositionals =
true;
119 result &= parseShort(iArguments, i);
131 oPositionals->push_back(arg);
148 TArguments arguments;
149 std::copy(iArgv + 1, iArgv + iArgc, std::back_inserter(arguments));
151 return parse(arguments, oPositionals);
164 const std::string whitespace =
" \t\n";
165 const std::string quotes =
"\"";
166 const std::string escapes =
"\\";
173 bool isQuoted =
false;
175 bool isEscaped =
false;
178 for (std::string::const_iterator ch = iArguments.begin(); ch != iArguments.end(); ++ch)
180 if (whitespace.find(*ch) != std::string::npos && !isQuoted)
184 result.push_back(token);
188 else if (quotes.find(*ch) != std::string::npos)
192 token.append(1, *ch);
211 else if (escapes.find(*ch) != std::string::npos)
215 token.append(1, *ch);
228 token.append(1, escape);
231 token.append(1, *ch);
235 result.push_back(token);
236 return parse(result, oPositionals);
241std::string ArgParser::usage()
const
243 std::ostringstream result;
246 if (!programName_.empty())
248 result <<
" " << programName_;
251 result <<
" [-v|--version] [-h|--help]";
253 for (TParameters::const_iterator pit = parameters_.begin(); pit != parameters_.end(); ++pit)
255 result <<
" " << (*pit)->format();
258 if (!positionals_.empty())
260 result <<
" " << positionals_;
269void ArgParser::subscribe(ArgParameter& iParameter)
271 const std::string& shortName = iParameter.shortName();
272 const std::string& longName = iParameter.longName();
276 if (shortName.empty() && longName.empty())
278 LASS_THROW(
"Subscribing parameter failed because both the short and the long names are "
279 "empty what makes it impossible to identify the parameter.");
284 if (!shortName.empty())
286 if (shortName.length() != 1 || !std::isalnum(shortName[0], std::locale()))
288 LASS_THROW(
"Subscribing parameter failed because the short name is not a single "
289 "alpha-numeric character.");
293 if (!isValidLongName(longName))
295 LASS_THROW(
"Subscribing parameter failed because the long name isn't valid.");
300 for (TParameters::const_iterator pit = parameters_.begin(); pit != parameters_.end(); ++pit)
302 ArgParameter* param = *pit;
303 if ((!shortName.empty() && param->shortName() == shortName) ||
304 (!longName.empty() && param->longName() == longName))
306 LASS_THROW(
"Subscribing parameter failed because there is already an parameter with "
307 "the same short or long name.");
312 parameters_.push_back(&iParameter);
317bool ArgParser::parseShort(
const TArguments& iArguments, TSize& ioIndex)
319 const std::string& arg = iArguments[ioIndex];
320 LASS_ASSERT(arg.length() > 1);
324 std::string shortName(arg, 1, 1);
325 LASS_ASSERT(shortName.length() == 1);
326 LASS_ASSERT(shortName[0] == arg[1]);
327 if (writeVersionOrHelp(shortName))
331 for (TParameters::iterator pit = parameters_.begin(); pit != parameters_.end(); ++pit)
333 ArgParameter* param = *pit;
334 if (param->shortName() == shortName)
338 std::string value =
"";
339 if (arg.length() > 2)
341 value = arg.substr(2);
348 if (ioIndex + 1 < iArguments.size())
350 std::string candidate = iArguments[ioIndex + 1];
351 if (candidate.length() > 0 && candidate[0] !=
'-')
358 param->setValue(value);
370 for (std::string::size_type i = 2; i < arg.length(); ++i)
372 shortName = arg.substr(i, 1);
373 LASS_ASSERT(shortName.length() == 1);
374 LASS_ASSERT(shortName[0] == arg[i]);
375 if (writeVersionOrHelp(shortName))
379 for (TParameters::iterator pit = parameters_.begin(); pit != parameters_.end(); ++pit)
381 ArgParameter* param = *pit;
382 if (param->shortName() == shortName)
392 LASS_COUT <<
"Bad program arguments: the argument '" << shortName
393 <<
"' can take a value. You cannot group it with other arguments like "
394 <<
"in '" << arg <<
"'.\n" << usage() <<
"\n";
406bool ArgParser::parseLong(
const TArguments& iArguments, TSize iIndex)
408 const std::string& arg = iArguments[iIndex];
409 LASS_ASSERT(arg.length() > 2);
413 std::string longName;
415 std::string::size_type equalPosition = arg.find(
'=');
416 if (equalPosition == std::string::npos)
418 longName = arg.substr(2);
423 longName = arg.substr(2, equalPosition - 2);
424 value = arg.substr(equalPosition + 1);
429 if (!isValidLongName(longName))
433 LASS_COUT <<
"Bad program arguments: the argument '--" << longName <<
"' is not a "
434 <<
"valid long parameter name.\n" << usage() <<
"\n";
439 if (writeVersionOrHelp(longName))
444 TParameters::iterator match = parameters_.end();
448 for (TParameters::iterator pit = parameters_.begin(); pit != parameters_.end(); ++pit)
450 ArgParameter* param = *pit;
451 if (param->longName() == longName)
460 if (match == parameters_.end())
462 for (std::string::size_type length = longName.length(); length > 0; --length)
464 TParameters::iterator candidate = parameters_.end();
465 bool isUnique =
true;
467 for (TParameters::iterator pit = parameters_.begin(); pit != parameters_.end(); ++pit)
469 ArgParameter* param = *pit;
470 if (param->longName().length() >= length)
472 if (param->longName().substr(1, length) == longName.substr(1, length))
474 isUnique = candidate == parameters_.end();
480 if (candidate != parameters_.end() && isUnique ==
true)
490 if (match == parameters_.end())
494 LASS_COUT <<
"Bad program arguments: the argument '--" << longName <<
"' is not as a "
495 <<
"long parameter name, nor is it a unique abbrevation of one.\n" << usage()
503 (*match)->setValue(value);
511bool ArgParser::isValidLongName(
const std::string& iLongName)
const
513 std::string extra =
"-";
515 for (std::string::size_type i = 0; i < iLongName.length(); ++i)
517 const char ch = iLongName[i];
518 if (!std::isalnum(ch, std::locale()) && extra.find(ch) == std::string::npos)
528bool ArgParser::writeVersionOrHelp(
const std::string& iArgument)
const
530 if (iArgument ==
"v" || iArgument ==
"version")
535 if (iArgument ==
"h" || iArgument ==
"help")
545void ArgParser::writeVersion()
const
547 LASS_COUT << programName_ <<
" version " << programVersion_ <<
"\n";
552void ArgParser::writeHelp()
const
562ArgParameter::~ArgParameter()
568const std::string& ArgParameter::shortName()
const
575const std::string& ArgParameter::longName()
const
582int ArgParameter::mode()
const
589bool ArgParameter::operator!()
const
596ArgParameter::operator bool()
const
603ArgParameter::ArgParameter(
ArgParser& iParser,
604 const std::string& iShortName,
605 const std::string& iLongName,
608 shortName_(iShortName),
609 longName_(iLongName),
613 parser_.subscribe(*
this);
618const std::string ArgParameter::names()
const
620 std::ostringstream result;
622 if (!shortName_.empty())
624 result <<
"-" << shortName_;
626 if (!longName_.empty())
628 if (!shortName_.empty())
632 result <<
"--" << longName_;
640bool ArgParameter::parserIsQuiet()
const
642 return parser_.isQuiet_;
647void ArgParameter::set()
654const std::string ArgParameter::format()
const
661bool ArgParameter::setValue(
const std::string& iValue)
663 return doSetValue(iValue);
668const std::string ArgParameter::doFormat()
const
670 std::ostringstream result;
671 result <<
"[" << names() <<
"]";
677bool ArgParameter::doSetValue(
const std::string& )
689 const std::string& iShortName,
690 const std::string& iLongName):
691 ArgParameter(iParser, iShortName, iLongName,
amNoValue)
699 ArgParameter(iParser, iFormat.shortName, iFormat.longName,
amNoValue)