29#ifndef ARGPARSE_NAMESPACE_NAME
30#define ARGPARSE_NAMESPACE_NAME argparse
41#include <initializer_list>
43#if __cplusplus > 201402L || _MSVC_LANG > 201402L
55 const size_t kSizeTypeEnd =
static_cast<size_t>(-1);
56 const size_t kHelpWidth = 80;
57 const size_t kHelpNameWidthPercent = 30;
59 bool isNumber(
const std::string& inStr)
61 const bool hasNegSign = inStr.at(0) ==
'-';
62 size_t dotPos = 0, expPos = 0;
63 size_t startPos =
static_cast<size_t>(hasNegSign);
64 for (
size_t curPos = startPos; curPos < inStr.size(); ++curPos)
66 const char curChar = inStr.at(curPos);
67 if (curChar >=
'0' && curChar <=
'9')
71 else if (curChar ==
'.'
72 && !dotPos && curPos != startPos && curPos != inStr.size() - 1)
76 else if ((curChar ==
'e' || curChar ==
'E')
77 && !expPos && curPos != startPos && curPos != inStr.size() - 1)
93 size_t getStringStreamLength(std::stringstream& showDesc)
95 showDesc.seekp(0, std::ios::end);
96 return showDesc.tellp();
135 Argument(
const std::string& positionalName =
"",
136 const std::string& shortName =
"",
137 const std::string& longName =
"",
138 const int argsCount = 1,
140 const bool required =
true,
141 const std::string& help =
"")
160 const std::string& longName =
"",
161 const int argsCount = 1,
163 const bool required =
true,
164 const std::string& help =
"")
166 return Argument(
"", shortName, longName, argsCount, argType, required, help);
176 const int argsCount = 1,
178 const bool required =
true,
179 const std::string& help =
"")
181 return Argument(positionalName,
"",
"", argsCount, argType, required, help);
326 Argument&
SetChoices(
const std::vector<std::string>& choices)
330 throw std::runtime_error(
"wrong type");
341 Argument&
SetChoices(std::initializer_list<const char*> choices)
343 return SetChoices(std::vector<std::string>(choices.begin(), choices.end()));
357 throw std::runtime_error(
"wrong type");
374 throw std::runtime_error(
"wrong type");
391 throw std::runtime_error(
"wrong type");
404 throw std::runtime_error(
"wrong type");
406 m_defaultBool.push_back(defaultArg);
418 throw std::runtime_error(
"wrong type");
420 m_defaultInt.push_back(defaultArg);
432 throw std::runtime_error(
"wrong type");
434 m_defaultLongLong.push_back(defaultArg);
446 throw std::runtime_error(
"wrong type");
448 m_defaultDouble.push_back(defaultArg);
460 throw std::runtime_error(
"wrong type");
462 m_defaultString.push_back(defaultArg);
474 throw std::runtime_error(
"wrong type");
476 m_defaultBool = defaultArg;
488 throw std::runtime_error(
"wrong type");
490 m_defaultInt = defaultArg;
498 Argument&
SetDefault(
const std::vector<long long>& defaultArg)
502 throw std::runtime_error(
"wrong type");
504 m_defaultLongLong = defaultArg;
516 throw std::runtime_error(
"wrong type");
518 m_defaultDouble = defaultArg;
526 Argument&
SetDefault(
const std::vector<std::string>& defaultArg)
530 throw std::runtime_error(
"wrong type");
532 m_defaultString = defaultArg;
546 bool m_hasDefault =
false;
547 std::vector<bool> m_defaultBool = {};
548 std::vector<int> m_defaultInt = {};
549 std::vector<long long> m_defaultLongLong = {};
550 std::vector<double> m_defaultDouble = {};
551 std::vector<std::string> m_defaultString = {};
553 friend ArgumentsObject;
569 const std::string& longName =
"",
570 const int argsCount = 1,
572 const bool required =
true,
573 const std::string& help =
"")
588 const int argsCount = 1,
590 const bool required =
true,
591 const std::string& help =
"")
682 return m_int.front();
758#if __cplusplus > 201402L || _MSVC_LANG > 201402L
769 return m_string.front();
773 case ArgTypeCast::e_int:
776 return m_int.front();
780 case ArgTypeCast::e_longlong:
787 case ArgTypeCast::e_double:
794 case ArgTypeCast::e_bool:
819 throw std::out_of_range(std::string(
"ArgumentParsed::") + getter
820 +
"() called on an argument that holds no value");
848 class ArgumentsObject
869 return m_parsed.size();
881 const auto position = m_names.find(name);
882 if (position == m_names.end())
887 const auto argument = m_parsed.find(position->second);
888 if (argument == m_parsed.end())
893 return argument->second;
904 void SetErrorString(
const std::string& error)
913 void ParseDefault(
const Argument& argObj,
const size_t position)
915 ArgumentParsed arg = ArgumentParsed();
917 arg.m_type = argObj.m_type;
919 if (argObj.m_type == ArgTypeCast::e_String)
921 arg.m_string = argObj.m_defaultString;
922 arg.m_count = argObj.m_defaultString.size();
924 else if (argObj.m_type == ArgTypeCast::e_bool)
926 arg.m_bool = argObj.m_defaultBool;
927 arg.m_count = argObj.m_defaultBool.size();
929 else if (argObj.m_type == ArgTypeCast::e_double)
931 arg.m_double = argObj.m_defaultDouble;
932 arg.m_count = argObj.m_defaultDouble.size();
934 else if (argObj.m_type == ArgTypeCast::e_longlong)
936 arg.m_longLong = argObj.m_defaultLongLong;
937 arg.m_count = argObj.m_defaultLongLong.size();
939 else if (argObj.m_type == ArgTypeCast::e_int)
941 arg.m_int = argObj.m_defaultInt;
942 arg.m_count = argObj.m_defaultInt.size();
945 m_parsed.emplace(position, arg);
946 if (!argObj.m_shortName.empty())
948 m_names[argObj.m_shortName] = position;
950 if (!argObj.m_longName.empty())
952 m_names[argObj.m_longName] = position;
954 if (!argObj.m_positionalName.empty())
956 m_names[argObj.m_positionalName] = position;
964 void CreateParsingStub(
const Argument& argObj,
const size_t position)
966 const auto argument = m_parsed.find(position);
967 if (argument == m_parsed.end())
969 ArgumentParsed arg = ArgumentParsed();
972 arg.m_type = argObj.m_type;
973 m_parsed.emplace(position, arg);
974 if (!argObj.m_shortName.empty())
976 m_names[argObj.m_shortName] = position;
978 if (!argObj.m_longName.empty())
980 m_names[argObj.m_longName] = position;
982 if (!argObj.m_positionalName.empty())
984 m_names[argObj.m_positionalName] = position;
994 bool Parse(
const Argument& argObj,
const size_t position,
const std::string& token)
996 const auto argument = m_parsed.find(position);
997 if (argument == m_parsed.end())
999 ArgumentParsed arg = ArgumentParsed();
1000 arg.m_exists =
true;
1002 arg.m_type = argObj.m_type;
1003 m_parsed.emplace(position, arg);
1004 if (!argObj.m_shortName.empty())
1006 m_names[argObj.m_shortName] = position;
1008 if (!argObj.m_longName.empty())
1010 m_names[argObj.m_longName] = position;
1012 if (!argObj.m_positionalName.empty())
1014 m_names[argObj.m_positionalName] = position;
1019 if (argument->second.m_type == ArgTypeCast::e_String)
1021 if (argObj.m_nargs != 0)
1023 if (argObj.m_choicesString.size())
1025 auto it = std::find_if(argObj.m_choicesString.begin(), argObj.m_choicesString.end(),
1026 [&token](
const std::string& str) ->
bool
1028 return token == str;
1030 if (it == argObj.m_choicesString.end())
1032 return InvalidateArgsOutOfChoice(argObj, token);
1035 argument->second.m_string.push_back(token);
1039 return InvalidateArgsTooMany(argObj);
1042 else if (argument->second.m_type == ArgTypeCast::e_bool)
1044 if (argObj.m_nargs != 0)
1046 if (token ==
"True" || token ==
"TRUE" || token ==
"true")
1048 argument->second.m_bool.push_back(
true);
1050 else if (token ==
"False" || token ==
"FALSE" || token ==
"false")
1052 argument->second.m_bool.push_back(
false);
1056 return InvalidateArgsCannotParse(argObj, token);
1061 return InvalidateArgsTooMany(argObj);
1064 else if (argument->second.m_type == ArgTypeCast::e_int)
1066 if (argObj.m_nargs != 0)
1068 if (isNumber(token))
1072 argument->second.m_int.push_back(std::stoi(token));
1074 int value = argument->second.m_int.back();
1076 if (argObj.m_choicesInt.size())
1078 auto it = std::find_if(argObj.m_choicesInt.begin(), argObj.m_choicesInt.end(),
1079 [value](
const int& integerValue) ->
bool
1081 return value == integerValue;
1083 if (it == argObj.m_choicesInt.end())
1085 return InvalidateArgsOutOfChoice(argObj, token);
1091 return InvalidateArgsCannotParse(argObj, token);
1096 return InvalidateArgsCannotParse(argObj, token);
1101 return InvalidateArgsTooMany(argObj);
1104 else if (argument->second.m_type == ArgTypeCast::e_longlong)
1106 if (argObj.m_nargs != 0)
1108 if (isNumber(token))
1112 argument->second.m_longLong.push_back(std::stoll(token));
1114 long long value = argument->second.m_longLong.back();
1116 if (argObj.m_choicesLongLong.size())
1118 auto it = std::find_if(argObj.m_choicesLongLong.begin(), argObj.m_choicesLongLong.end(),
1119 [value](
const long long& longLongVal) ->
bool
1121 return value == longLongVal;
1123 if (it == argObj.m_choicesLongLong.end())
1125 return InvalidateArgsOutOfChoice(argObj, token);
1131 return InvalidateArgsCannotParse(argObj, token);
1136 return InvalidateArgsCannotParse(argObj, token);
1141 return InvalidateArgsTooMany(argObj);
1144 else if (argument->second.m_type == ArgTypeCast::e_double)
1146 if (argObj.m_nargs != 0)
1148 if (isNumber(token))
1152 argument->second.m_double.push_back(std::stod(token));
1154 double value = argument->second.m_double.back();
1156 if (argObj.m_choicesDouble.size())
1158 auto it = std::find_if(argObj.m_choicesDouble.begin(), argObj.m_choicesDouble.end(),
1159 [value](
const double& doubleVal) ->
bool
1161 return std::numeric_limits<double>::epsilon() >= abs(doubleVal - value);
1163 if (it == argObj.m_choicesDouble.end())
1165 return InvalidateArgsOutOfChoice(argObj, token);
1171 return InvalidateArgsCannotParse(argObj, token);
1176 return InvalidateArgsCannotParse(argObj, token);
1181 return InvalidateArgsTooMany(argObj);
1185 argument->second.m_count += 1;
1193 bool InvalidateArgsOutOfChoice(
const Argument& argObj,
const std::string& token)
1195 const std::string& name = argObj.m_longName.empty() ? (argObj.m_shortName.empty() ? argObj.m_positionalName : argObj.m_shortName) : argObj.m_longName;
1197 SetErrorString(
"Value '" + token +
"' is out of choices for \"" + name +
"\"");
1205 bool InvalidateArgsTooMany(
const Argument& argObj)
1207 const std::string& name = argObj.m_longName.empty() ? (argObj.m_shortName.empty() ? argObj.m_positionalName : argObj.m_shortName) : argObj.m_longName;
1209 SetErrorString(
"too many arguments for \"" + name +
"\"");
1218 bool InvalidateArgsCannotParse(
const Argument& argObj,
const std::string& token)
1220 const std::string& name = argObj.m_longName.empty() ? (argObj.m_shortName.empty() ? argObj.m_positionalName : argObj.m_shortName) : argObj.m_longName;
1222 SetErrorString(
"cannot parse [\"" + token +
"\"] for argument \"" + name +
"\"");
1227 bool m_isValid =
false;
1228 std::string m_error;
1229 std::map<const size_t, ArgumentParsed> m_parsed;
1230 std::map<const std::string, size_t> m_names;
1232 friend ArgumentParser;
1253 m_description = description;
1262 m_allowAbbrev = allowAbbrev;
1272 m_ignoreUnknownArgs = ignoreUnknownArgs;
1281 m_addHelp = addHelp;
1293 m_epilogue = epilogue;
1323 throw std::runtime_error(
"Short,long or positional names of argument are empty.\n"
1324 "At least one name should been specified.");
1328 throw std::runtime_error(
"Positional argument " + arg.
m_positionalName +
" declared aside with short/long name\n"
1329 "Positional argument shouldn't have any short/long name.");
1335 throw std::runtime_error(
"No need to declare choice for bool type");
1339 throw std::runtime_error(
"Only int choices should been declared");
1343 throw std::runtime_error(
"Only long long choices should been declared");
1347 throw std::runtime_error(
"Only double choices should been declared");
1351 throw std::runtime_error(
"Only string choices should been declared");
1363 std::string _pref{ m_prefix };
1364 std::string _doublePref{ m_prefix, m_prefix };
1366 for (
auto& el : m_knownArgumentNames)
1368 if (el.second.argNameType == KnownNameType::e_Short)
1370 m_knownArgumentNamesInternal[_pref + el.first] = el.second;
1374 m_knownArgumentNamesInternal[_doublePref + el.first] = el.second;
1380 bool shortHelpAlreadyExists =
false, longHelpAlreadyExists =
false;
1381 auto foundArgObject = m_knownArgumentNamesInternal.find(_pref +
"h");
1382 shortHelpAlreadyExists = foundArgObject != m_knownArgumentNamesInternal.end();
1383 foundArgObject = m_knownArgumentNamesInternal.find(_doublePref +
"help");
1384 longHelpAlreadyExists = foundArgObject != m_knownArgumentNamesInternal.end();
1385 if (!shortHelpAlreadyExists || !longHelpAlreadyExists)
1391 if (!shortHelpAlreadyExists)
1393 m_knownArgumentNamesInternal[_pref + arg.
m_shortName] = { m_arguments.size()-1, KnownNameType::e_Short };
1395 if (!longHelpAlreadyExists)
1397 m_knownArgumentNamesInternal[_doublePref + arg.
m_longName] = { m_arguments.size()-1, KnownNameType::e_Long };
1402 bool positionalArgsEndFlag =
false;
1403 size_t currentArgumentObjectIndex = kSizeTypeEnd;
1404 std::vector<std::string> positionalArgs;
1406 for (
size_t i =0; i < args.size(); ++i)
1408 const std::string& el = args[i];
1409 auto foundArgObject = m_knownArgumentNamesInternal.find(el);
1410 if (foundArgObject == m_knownArgumentNamesInternal.end() && m_allowAbbrev)
1414 bool ambiguous =
false;
1415 std::string abbrev = ResolveAbbreviation(el, _doublePref, ambiguous);
1418 argObj.SetErrorString(
"Ambiguous option \"" + el
1419 +
"\" matches more than one argument");
1422 if (!abbrev.empty())
1424 foundArgObject = m_knownArgumentNamesInternal.find(abbrev);
1427 if (foundArgObject != m_knownArgumentNamesInternal.end())
1429 currentArgumentObjectIndex = foundArgObject->second.position;
1431 Argument& argument = m_arguments[currentArgumentObjectIndex];
1434 if (!argObj.Parse(argument, currentArgumentObjectIndex, el))
1441 argObj.CreateParsingStub(argument, currentArgumentObjectIndex);
1444 positionalArgsEndFlag =
true;
1447 else if (!positionalArgsEndFlag)
1451 positionalArgs.push_back(el);
1453 else if (el.find(_pref) == 0 || el.find(_doublePref) == 0)
1455 if (!
_unknownArgumentHit(argObj, i+1, currentArgumentObjectIndex, positionalArgsEndFlag, el))
1462 positionalArgs.push_back(el);
1466 else if (el.find(_pref) == 0 || el.find(_doublePref) == 0)
1468 if (!
_unknownArgumentHit(argObj, i+1, currentArgumentObjectIndex, positionalArgsEndFlag, el))
1475 if (currentArgumentObjectIndex != kSizeTypeEnd)
1477 Argument& argument = m_arguments[currentArgumentObjectIndex];
1479 if (!argObj.Parse(argument, currentArgumentObjectIndex, el))
1486 if (!positionalArgs.empty())
1488 if (m_positionalArgumentNames.empty())
1490 argObj.SetErrorString(
"Unknown positional argument:" + positionalArgs.front());
1493 size_t minimumRequiredPositionalCount = 0;
1494 size_t infiniteRequiredPositionalCount = 0;
1495 size_t optionalPositionalCount = 0;
1497 for (
auto& el : m_positionalArgumentNames)
1499 if (m_arguments[el.positionInArguments].m_required)
1501 minimumRequiredPositionalCount += m_arguments[el.positionInArguments].m_nargs ==
kFromOneToInfiniteArgCount ? 1 : m_arguments[el.positionInArguments].m_nargs;
1506 ++optionalPositionalCount;
1509 if (minimumRequiredPositionalCount > positionalArgs.size())
1511 argObj.SetErrorString(
"Too few positional arguments: required " + std::to_string(minimumRequiredPositionalCount) +
" got " + std::to_string(positionalArgs.size()));
1515 size_t totalTokensForRequiredNargs = 1;
1516 size_t additionalTokensForFirstRequiredNarg = 0;
1517 size_t howMuchOptionalArgsCanBeParsed = positionalArgs.size() - minimumRequiredPositionalCount;
1518 if (howMuchOptionalArgsCanBeParsed > optionalPositionalCount)
1520 if (infiniteRequiredPositionalCount == 0)
1522 argObj.SetErrorString(
"Too many positional arguments!");
1527 totalTokensForRequiredNargs = (howMuchOptionalArgsCanBeParsed - optionalPositionalCount) / infiniteRequiredPositionalCount;
1528 additionalTokensForFirstRequiredNarg = (howMuchOptionalArgsCanBeParsed - optionalPositionalCount) % infiniteRequiredPositionalCount;
1530 howMuchOptionalArgsCanBeParsed = optionalPositionalCount;
1534 size_t currentTokenPosition = 0;
1535 size_t optionalParsed = 0;
1537 for (
auto& el : m_positionalArgumentNames)
1539 Argument& argument = m_arguments[el.positionInArguments];
1540 argObj.CreateParsingStub(argument, el.positionInArguments);
1542 if (m_arguments[el.positionInArguments].m_required)
1547 for (
size_t i = 0; i < static_cast<size_t>(m_arguments[el.positionInArguments].m_nargs); ++i)
1549 if (!argObj.Parse(argument, el.positionInArguments, positionalArgs[currentTokenPosition]))
1553 ++currentTokenPosition;
1558 size_t addtionalArg = 0;
1559 if (additionalTokensForFirstRequiredNarg > 0)
1562 --additionalTokensForFirstRequiredNarg;
1564 for (
size_t i = 0; i < totalTokensForRequiredNargs + addtionalArg; ++i)
1566 if (!argObj.Parse(argument, el.positionInArguments, positionalArgs[currentTokenPosition]))
1570 ++currentTokenPosition;
1574 else if (optionalParsed <= howMuchOptionalArgsCanBeParsed)
1576 if (!argObj.Parse(argument, el.positionInArguments, positionalArgs[currentTokenPosition]))
1580 ++currentTokenPosition;
1586 for (
size_t i = 0; i < m_arguments.size(); ++i)
1588 auto el = m_arguments[i];
1589 const std::string& name = el.m_longName.empty() ? (el.m_shortName.empty() ? el.m_positionalName : el.m_shortName) : el.m_longName;
1603 argObj.SetErrorString(
"Wrong arguments count for argument with name \"" + name +
"\" got = " + std::to_string(parsedArg.
GetArgumentCount()));
1607 else if (el.HasDefault())
1609 argObj.ParseDefault(el, i);
1611 else if (el.m_required)
1613 argObj.SetErrorString(
"Required argument with name \"" + name +
"\" does not exist");
1631 if (m_ignoreUnknownArgs)
1633 currentArgumentObjectIndex = kSizeTypeEnd;
1634 positionalArgsEndFlag =
true;
1637 std::stringstream ss;
1638 ss <<
"Unknown input argument: \"" << el <<
"\" at position " << positionInInput;
1639 argObj.SetErrorString(ss.str());
1651 std::vector<std::string> args;
1652 for (
int i = 1; i < argc; ++i)
1654 args.emplace_back(argv[i]);
1664 std::string
GetHelp(
size_t width = kHelpWidth,
size_t nameWidthPercent = kHelpNameWidthPercent)
1666 width = width < kHelpWidth ? kHelpWidth : width;
1667 size_t nameWidthInHelp = nameWidthPercent * width / 100;
1668 width -= nameWidthInHelp;
1673 std::stringstream usage;
1674 if (!m_usage.empty())
1681 usage << m_name <<
" ";
1682 if (m_positionalArgumentNames.size())
1684 for (
auto& el : m_positionalArgumentNames)
1686 Argument& arg = m_arguments[el.positionInArguments];
1687 MakeUsageForName(arg, usage);
1690 for (
auto& el : m_arguments)
1692 if (el.m_positionalName.empty())
1694 MakeUsageForName(el, usage);
1699 if (!m_description.empty())
1701 AddAdditionalDescription(usage, m_description, width+nameWidthInHelp);
1704 if (m_positionalArgumentNames.size())
1706 usage <<
"\n\n" <<
"positional arguments:\n\n";
1707 for (
auto& el : m_positionalArgumentNames)
1709 Argument& arg = m_arguments[el.positionInArguments];
1710 MakeDescriptionForArg(arg, usage, nameWidthInHelp, width);
1714 if (m_arguments.size() > m_positionalArgumentNames.size())
1716 usage <<
"\n\n" <<
"named arguments:\n\n";
1717 for (
auto& el : m_arguments)
1719 if (el.m_positionalName.empty())
1721 MakeDescriptionForArg(el, usage, nameWidthInHelp, width);
1726 if (!m_epilogue.empty())
1728 AddAdditionalDescription(usage, m_epilogue, width+nameWidthInHelp);
1742 result.reserve(text.size());
1743 size_t lineStart = 0;
1744 while (lineStart <= text.size())
1746 size_t nl = text.find(
'\n', lineStart);
1747 size_t lineEnd = (nl == std::string::npos) ? text.size() : nl;
1748 size_t last = lineEnd;
1749 while (last > lineStart && (text[last - 1] ==
' ' || text[last - 1] ==
'\t'))
1753 result.append(text, lineStart, last - lineStart);
1754 if (nl == std::string::npos)
1758 result.push_back(
'\n');
1775 std::string ResolveAbbreviation(
1776 const std::string& token,
const std::string& doublePref,
bool& ambiguous)
1781 if (token.size() <= doublePref.size()
1782 || token.compare(0, doublePref.size(), doublePref) != 0)
1784 return std::string();
1788 for (
auto it = m_knownArgumentNamesInternal.begin();
1789 it != m_knownArgumentNamesInternal.end(); ++it)
1791 if (it->second.argNameType == KnownNameType::e_Long
1792 && it->first.size() > token.size()
1793 && it->first.compare(0, token.size(), token) == 0)
1798 return std::string();
1809 void _addArg(
const Argument& arg)
1811 size_t currentSize = m_arguments.size();
1812 if (!arg.m_shortName.empty())
1814 if (m_knownArgumentNames.find(arg.m_shortName) == m_knownArgumentNames.end())
1816 m_knownArgumentNames[arg.m_shortName] = { currentSize, KnownNameType::e_Short };
1820 throw std::runtime_error(
"Short name \"" + arg.m_shortName +
"\" already exists");
1823 if (!arg.m_longName.empty())
1825 if (m_knownArgumentNames.find(arg.m_longName) == m_knownArgumentNames.end())
1827 m_knownArgumentNames[arg.m_longName] = { currentSize, KnownNameType::e_Long };
1831 throw std::runtime_error(
"Long name \"" + arg.m_longName +
"\" already exists");
1834 if (!arg.m_positionalName.empty())
1836 auto it = std::find_if(m_positionalArgumentNames.begin(), m_positionalArgumentNames.end(), [&arg](PositionalNamesStruct& posarg)->bool {return posarg.argName == arg.m_positionalName; });
1837 if (it == m_positionalArgumentNames.end())
1839 m_positionalArgumentNames.emplace_back(m_arguments.size(), arg.m_positionalName);
1841 else if (arg.m_required && (arg.m_nargs == 0 || arg.m_nargs == kAnyArgCount))
1843 throw std::runtime_error(
"Required positional argument with name \"" + arg.m_positionalName +
"\" cannot be with zero count");
1845 else if (!arg.m_required && arg.m_nargs != 1)
1847 throw std::runtime_error(
"Non required positional argument with name \"" + arg.m_positionalName +
"\" should be with count 1");
1851 throw std::runtime_error(
"Positional name \"" + arg.m_positionalName +
"\" already exists");
1855 m_arguments.emplace_back(arg);
1861 void MakeUsageForName(Argument& arg, std::stringstream& usage)
1863 if (!arg.m_required)
1867 std::stringstream showName;
1868 if (arg.m_choicesDouble.size() + arg.m_choicesInt.size() + arg.m_choicesLongLong.size() + arg.m_choicesString.size())
1871 if (arg.m_type == ArgTypeCast::e_String)
1873 MakeChoicesToString<std::string>(showName, arg.m_choicesString);
1875 else if (arg.m_type == ArgTypeCast::e_int)
1877 MakeChoicesToString<int>(showName, arg.m_choicesInt);
1879 else if (arg.m_type == ArgTypeCast::e_double)
1881 MakeChoicesToString<double>(showName, arg.m_choicesDouble);
1883 else if (arg.m_type == ArgTypeCast::e_longlong)
1885 MakeChoicesToString<long long>(showName, arg.m_choicesLongLong);
1891 if (!arg.m_positionalName.empty())
1893 showName << arg.m_positionalName;
1895 else if (!arg.m_shortName.empty())
1897 showName << arg.m_shortName;
1901 showName << arg.m_longName;
1904 if (!arg.m_positionalName.empty())
1906 usage << showName.str();
1908 if (!arg.m_shortName.empty())
1910 usage << m_prefix << arg.m_shortName;
1913 if (!arg.m_longName.empty())
1915 if (!arg.m_shortName.empty())
1919 usage << m_prefix << m_prefix << arg.m_longName;
1922 if (arg.m_nargs == kAnyArgCount)
1924 usage <<
" [" << showName.str() <<
"[" << showName.str() <<
" ...]]";
1926 else if (arg.m_nargs == kFromOneToInfiniteArgCount)
1928 usage <<
" [" << showName.str() <<
" ...]";
1930 else if (arg.m_nargs != 0)
1933 usage << showName.str();
1934 for (
size_t i = 1; i < static_cast<size_t>(arg.m_nargs); ++i)
1936 usage <<
" " << showName.str();
1940 if (!arg.m_required)
1956 void MakeDescriptionForArg(Argument& arg, std::stringstream& description,
size_t nameLen,
size_t descLen)
1958 std::stringstream showName;
1959 std::stringstream showDesc;
1960 if (!arg.m_positionalName.empty())
1962 if (arg.m_choicesDouble.size() + arg.m_choicesInt.size() + arg.m_choicesLongLong.size() + arg.m_choicesString.size())
1965 if (arg.m_type == ArgTypeCast::e_String)
1967 MakeChoicesToString<std::string>(showName, arg.m_choicesString);
1969 else if (arg.m_type == ArgTypeCast::e_int)
1971 MakeChoicesToString<int>(showName, arg.m_choicesInt);
1973 else if (arg.m_type == ArgTypeCast::e_double)
1975 MakeChoicesToString<double>(showName, arg.m_choicesDouble);
1977 else if (arg.m_type == ArgTypeCast::e_longlong)
1979 MakeChoicesToString<long long>(showName, arg.m_choicesLongLong);
1985 showName << arg.m_positionalName;
1988 else if (!arg.m_shortName.empty())
1990 showName << m_prefix << arg.m_shortName;
1991 if (!arg.m_longName.empty())
1993 showName <<
"," << m_prefix << m_prefix << arg.m_longName;
1999 showName << m_prefix << m_prefix << arg.m_longName;
2002 showDesc << arg.m_help;
2005 showDesc << (arg.m_help.empty() ?
"" :
" ") <<
"Type: " << m_enumToString[arg.m_type] <<
". ";
2008 if ((!arg.m_shortName.empty() || !arg.m_longName.empty())
2009 && (arg.m_choicesDouble.size() + arg.m_choicesInt.size() + arg.m_choicesLongLong.size() + arg.m_choicesString.size()))
2011 showDesc <<
" Choices:";
2012 if (arg.m_type == ArgTypeCast::e_String)
2014 MakeChoicesToString<std::string>(showDesc, arg.m_choicesString);
2016 else if (arg.m_type == ArgTypeCast::e_int)
2018 MakeChoicesToString<int>(showDesc, arg.m_choicesInt);
2020 else if (arg.m_type == ArgTypeCast::e_double)
2022 MakeChoicesToString<double>(showDesc, arg.m_choicesDouble);
2024 else if (arg.m_type == ArgTypeCast::e_longlong)
2026 MakeChoicesToString<long long>(showDesc, arg.m_choicesLongLong);
2031 showDesc << (arg.m_nargs ?
"Args count: " :
"");
2032 switch (arg.m_nargs)
2035 showDesc <<
"any. ";
2038 showDesc <<
" at least one. ";
2043 showDesc << arg.m_nargs <<
" ";
2046 description << showName.str();
2047 size_t currentLen = getStringStreamLength(showName);
2049 size_t spaceFillerSize = nameLen - currentLen;
2050 if (currentLen >= nameLen - 1)
2052 description <<
"\n";
2053 spaceFillerSize = nameLen;
2057 std::string filler(spaceFillerSize,
' ');
2058 description << filler;
2063 filler = std::string(nameLen,
' ');
2065 for (std::string s; showDesc >> s; )
2067 if (currentLen > descLen)
2070 description <<
"\n" << filler;
2072 description << s <<
" ";
2073 currentLen += s.size() + 1;
2076 description <<
"\n";
2085 void AddAdditionalDescription(std::stringstream& description,
const std::string& additionalDesc,
size_t descLen)
2087 description <<
"\n";
2088 size_t currentLen = 0;
2089 std::stringstream buffer{ additionalDesc };
2090 for (std::string s; buffer >> s; )
2092 if (currentLen > descLen)
2095 description <<
"\n";
2097 description << s <<
" ";
2098 currentLen += s.size() + 1;
2108 template<
typename T>
2109 void MakeChoicesToString(std::stringstream& outSstream, std::vector<T>& choices)
2111 outSstream << choices.front();
2112 for (
size_t i = 1; i < choices.size(); ++i)
2114 outSstream <<
", " << choices[i];
2119 enum class KnownNameType :
int
2124 struct KnownNamesStruct
2127 KnownNameType argNameType;
2130 struct PositionalNamesStruct
2132 PositionalNamesStruct(
const size_t position,
const std::string& name)
2133 :positionInArguments(position)
2136 size_t positionInArguments;
2137 std::string argName;
2142 bool m_allowAbbrev =
true;
2144 bool m_addHelp =
true;
2146 bool m_ignoreUnknownArgs =
false;
2148 char m_prefix =
'-';
2155 std::string m_description{
"" };
2158 std::string m_epilogue{
"" };
2161 std::string m_usage{
"" };
2163 std::vector<Argument> m_arguments;
2165 std::vector<PositionalNamesStruct> m_positionalArgumentNames;
2167 std::map<std::string, KnownNamesStruct> m_knownArgumentNames;
2170 std::map<std::string, KnownNamesStruct> m_knownArgumentNamesInternal;
2172 std::map<const ArgTypeCast, const std::string> m_enumToString
2174 {ArgTypeCast::e_String,
"STRING" },
2175 {ArgTypeCast::e_int,
"INT" },
2176 {ArgTypeCast::e_longlong,
"LONG_LONG"},
2177 {ArgTypeCast::e_double,
"DOUBLE"},
2178 {ArgTypeCast::e_bool,
"BOOL"}
This class represents argument configuration which should be passed to ArgumentParser objects instanc...
Argument & SetChoices(const std::vector< std::string > &choices)
Handy setter of valid choices for arguments with string type.
std::string m_shortName
arguments short name for non positional argument only shot name used in input with 1 prefix
Argument & SetDefault(long long defaultArg)
Handy setter for single default argument of long long type.
std::vector< int > m_choicesInt
vector of integers to validate arguments input data.
Argument & SetDefault(bool defaultArg)
Handy setter for single default argument of bool type.
Argument & SetLongName(const std::string &name)
Handy setter for long named argument.
Argument & SetShortName(const std::string &name)
Handy setter for short named argument.
Argument & SetAnyNumberOfArgumentsButAtLeastOne()
Handy setter for argument count with self declared name.
Argument & SetDefault(const std::vector< int > &defaultArg)
Handy setter for vector of default arguments of int type.
static Argument CreatePositionalArgument(const std::string &positionalName="", const int argsCount=1, ArgTypeCast argType=ArgTypeCast::e_String, const bool required=true, const std::string &help="")
Default function for named arguments.
std::vector< long long > m_choicesLongLong
vector of long longs to validate arguments input data.
Argument & SetHelp(const std::string &help)
Handy setter for additional help.
Argument & SetDefault(std::string defaultArg)
Handy setter for single default argument of string type.
Argument & SetArgumentIsFlag()
Handy setter for argument which is actually a flag (e.g.
Argument & SetDefault(const std::vector< bool > &defaultArg)
Handy setter for vector of default arguments of bool type.
Argument & SetAnyNumberOfArguments()
Handy setter for argument count with self declared name.
Argument & SetDefault(const std::vector< std::string > &defaultArg)
Handy setter for vector of default arguments of string type.
Argument & SetDefault(const std::vector< double > &defaultArg)
Handy setter for vector of default arguments of double type.
std::vector< std::string > m_choicesString
vector of strings to validate arguments input data.
std::string m_help
additional help info for argument Will be part of generated help
Argument & SetPositionalName(const std::string &name)
Handy setter for positional argument.
ArgTypeCast m_type
Variable that hold type of argument.
std::string m_positionalName
name of positional argument positional arguments name used only to access desired argument from code
Argument & SetChoices(std::initializer_list< const char * > choices)
Overload so a braced list of string literals – e.g.
Argument & SetNumberOfArguments(int amount)
setter function for m_nargs with desired amount
Argument & SetChoices(const std::vector< double > &choices)
Handy setter of valid choices for arguments with double type.
Argument & SetDefault(double defaultArg)
Handy setter for single default argument of double type.
bool m_required
required flag argument If required argument is not set in command line then parsing will fail.
Argument & SetDefault(int defaultArg)
Handy setter for single default argument of int type.
int m_nargs
variable that indicates count of argument in input use "kAnyArgCount" or "kFromOneToInfiniteArgCount"...
Argument & SetChoices(const std::vector< long long > &choices)
Handy setter of valid choices for arguments with long long type.
Argument & SetChoices(const std::vector< int > &choices)
Handy setter of valid choices for arguments with int type.
bool HasDefault() const
Getter to indicate does argument has any default value.
static Argument CreateNamedArgument(const std::string &shortName="", const std::string &longName="", const int argsCount=1, ArgTypeCast argType=ArgTypeCast::e_String, const bool required=true, const std::string &help="")
Default constructor positional arguments.
Argument & SetRequired(bool required)
Setter function to flag,.
Argument & SetType(ArgTypeCast argType)
Setter function for type of current argument.
std::string m_longName
arguments long name.
std::vector< double > m_choicesDouble
vector of double to validate arguments input data.
Argument & SetDefault(const std::vector< long long > &defaultArg)
Handy setter for vector of default arguments of long long type.
Class which represent actual parsed argument in case of successfully parsing.
std::vector< int > m_int
container of parse int arguments
std::vector< double > GetAsVecDouble() const
Get result as vector double for double type arguments.
std::vector< long long > m_longLong
container of parsed long long arguments
std::vector< double > m_double
container of parsed double arguments
int GetAsInt() const
Get result as single int for int type arguments.
double GetAsDouble() const
Get result as single double for double type arguments.
size_t GetArgumentCount()
get actual count of argument, in case of various arguments count.
static void ThrowIfEmpty(bool empty, const char *getter)
Guard for the scalar getters.
bool GetAsBool() const
Get result as single bool for bool type arguments.
std::vector< long long > GetAsVecLongLong() const
Get result as vector long long for long long type arguments.
std::vector< bool > m_bool
container of parsed bool arguments
std::vector< std::string > GetAsVecString() const
Get result as vector string for string type arguments.
std::vector< int > GetAsVecInt() const
Get result as vector int for int type arguments.
std::string GetAsString() const
Get result as single string for string type arguments.
bool GetArgumentExists()
Does argument exists.
std::vector< bool > GetAsVecBool() const
Get result as vector bool for bool type arguments.
long long GetAsLongLong() const
Get result as single long long for long long type arguments.
bool m_exists
flag about is argument exists
ArgTypeCast m_type
type of argument
size_t m_count
count of arguments properties
std::vector< std::string > m_string
container of parsed string arguments
Main class of argument parser hold all user arguments from code and orchestrate other classes in orde...
std::string GetHelp(size_t width=kHelpWidth, size_t nameWidthPercent=kHelpNameWidthPercent)
Function to get help string.
ArgumentsObject ParseArgs(const int argc, char **argv)
This function just converts argc and argv to vector of token.
ArgumentParser & SetDescription(const std::string &description) noexcept
Overload default description for auto-generated command line.
ArgumentParser & SetPrefixChars(const char charSym) noexcept
Function to override default prefix.
ArgumentParser(const std::string &name) noexcept
Constructor for ArgumentParser.
void AddArgument(const Argument &arg)
Function to add arguments specification to command line parser.
ArgumentParser & SetIgnoreUnknownArgs(bool ignoreUnknownArgs) noexcept
Setter to ignore unknown argument while parsing.
ArgumentParser & SetAllowAbbrev(bool allowAbbrev) noexcept
Allows long options to be abbreviated if the abbreviation is unambiguous.
static std::string TrimTrailingSpacesPerLine(const std::string &text)
Removes trailing spaces/tabs from every line of the help text.
ArgumentsObject ParseArgs(const std::vector< std::string > &args)
Main function of parsing argument.
ArgumentParser & SetUsage(const std::string &usage) noexcept
Program usage examples.
bool _unknownArgumentHit(ArgumentsObject &argObj, const size_t positionInInput, size_t ¤tArgumentObjectIndex, bool &positionalArgsEndFlag, const std::string &el)
function which resolves unknown arguments presence
ArgumentParser & SetAddHelp(bool addHelp) noexcept
Add a - h / –help option to the parser.
ArgumentParser & SetEpilogue(const std::string &epilogue) noexcept
This function allows to set final message after program description and before argument list descript...
Class that carries result of real parsing Indicates if parsing is successful and allows to get Argume...
const std::string & GetErrorString()
Function to get error message in case of parsing failure.
size_t ParsedArgsCount() const
I don't know when you could need this info.
bool IsArgValid() const
Indicates if parsing was successful.
ArgumentParsed GetArg(const std::string &name)
Getter function to get ArgumentParsed object.
namespace of argument parser constants and Classes can be changed if ARGPARSE_NAMESPACE_NAME macro sp...
const int kFromOneToInfiniteArgCount
constant to indicate arguments with various count from 1 to infinite
ArgTypeCast
Supported types for argument If needed type is not in this list, then just use e_String.
Argument CreatePositionalArgument(const std::string &positionalName="", const int argsCount=1, ArgTypeCast argType=ArgTypeCast::e_String, const bool required=true, const std::string &help="")
Helper function to create positional argument.
Argument CreateNamedArgument(const std::string &shortName="", const std::string &longName="", const int argsCount=1, ArgTypeCast argType=ArgTypeCast::e_String, const bool required=true, const std::string &help="")
Helper function to create named argument.
const int kAnyArgCount
constant to indicate arguments with various count from 0 to infinite
Aggregate description of a named argument, for keyword-style construction.
Aggregate description of a positional argument, for keyword-style construction with C++20 designated ...