17 #ifndef COM_BORA_SOFTWARE__BALAU_APPLICATION__COMMAND_LINE 18 #define COM_BORA_SOFTWARE__BALAU_APPLICATION__COMMAND_LINE 101 const std::string & shortSwitch,
102 const std::string & longSwitch,
104 const std::string & documentation) {
105 keysBySwitch[shortSwitch] = key;
106 keysBySwitch[longSwitch] = key;
107 optionsByKey[key] = Option(key, shortSwitch, longSwitch, hasValue, documentation);
120 const std::string & shortSwitch,
122 const std::string & documentation) {
123 keysBySwitch[shortSwitch] = key;
124 optionsByKey[key] = Option(key, shortSwitch,
"", hasValue, documentation);
136 const std::string & shortSwitch,
137 const std::string & longSwitch,
138 const std::string & helpDocumentation) {
139 keysBySwitch[shortSwitch] = helpKey;
140 keysBySwitch[longSwitch] = helpKey;
141 optionsByKey[helpKey] = Option(helpKey, shortSwitch, longSwitch,
false, helpDocumentation);
149 commandLineHasFinalValue = HasFinalValue::Yes;
157 commandLineHasFinalValue = HasFinalValue::Maybe;
174 public:
void parse(
int argc,
char * argv[],
bool ignoreFirst) {
175 std::vector<std::string> args(static_cast<unsigned long>(argc));
177 for (
int m = 0; m < argc; m++) {
178 args[m] = std::string(argv[m]);
181 parse(args, ignoreFirst);
195 public:
void parse(
int argc,
const char * argv[],
bool ignoreFirst) {
196 std::vector<std::string> args(static_cast<unsigned long>(argc));
198 for (
int m = 0; m < argc; m++) {
199 args[m] = std::string(argv[m]);
202 parse(args, ignoreFirst);
219 public:
void parse(
const std::vector<std::string> & args,
bool ignoreFirst) {
222 parsedValuesByKey.clear();
224 if (args.empty() || (ignoreFirst && args.size() == 1)) {
225 if (commandLineHasFinalValue == HasFinalValue::Yes) {
233 ? determineStyle(args[ignoreFirst ? 1 : 0], ignoreFirst ? args.size() - 1: args.size())
237 parseSwitchEqualsValue(derivedStyle, args, ignoreFirst);
239 parseSwitchSpaceValue(derivedStyle, args, ignoreFirst);
249 return parsedValuesByKey.find(key) != parsedValuesByKey.end();
259 return finalValues.size();
272 if (parsedValuesByKey.find(key) == parsedValuesByKey.end()) {
276 return parsedValuesByKey.at(key);
283 if (parsedValuesByKey.find(key) == parsedValuesByKey.end()) {
287 return parsedValuesByKey.at(key);
299 auto parse = [] (
const std::string & str) {
return std::stoi(str); };
300 return getOptionAs<short, int>(key,
"a short integer", parse);
310 auto parse = [] (
const std::string & str) {
return std::stoull(str); };
311 return getOptionAs<unsigned short, unsigned long long>(key,
"an unsigned short integer", parse);
321 auto parse = [] (
const std::string & str) {
return std::stoi(str); };
322 return getOptionAs<int, int>(key,
"an integer", parse);
332 auto parse = [] (
const std::string & str) {
return std::stoull(str); };
333 return getOptionAs<unsigned int, unsigned long long>(key,
"an unsigned integer", parse);
343 auto parse = [] (
const std::string & str) {
return std::stoll(str); };
344 return getOptionAs<long long, long long>(key,
"a long integer", parse);
354 auto parse = [] (
const std::string & str) {
return std::stoull(str); };
355 return getOptionAs<unsigned long long, unsigned long long>(key,
"an unsigned long long integer", parse);
367 auto parse = [] (
const std::string & str) {
return std::stoi(str); };
368 return getOptionAs<short, int>(key,
"a short integer", parse,
true, defaultValue);
378 auto parse = [] (
const std::string & str) {
return std::stoull(str); };
379 return getOptionAs<unsigned short, unsigned long long>(key,
"an unsigned short integer", parse,
true, defaultValue);
389 auto parse = [] (
const std::string & str) {
return std::stoi(str); };
390 return getOptionAs<int, int>(key,
"an integer", parse,
true, defaultValue);
400 auto parse = [] (
const std::string & str) {
return std::stoull(str); };
401 return getOptionAs<unsigned int, unsigned long long>(key,
"an unsigned integer", parse,
true, defaultValue);
411 auto parse = [] (
const std::string & str) {
return std::stoll(str); };
412 return getOptionAs<long long, long long>(key,
"a long integer", parse,
true, defaultValue);
422 auto parse = [] (
const std::string & str) {
return std::stoull(str); };
423 return getOptionAs<unsigned long long, unsigned long long>(key,
"an unsigned long long integer", parse,
true, defaultValue);
435 auto parse = [] (
const std::string & str) {
return std::stof(str); };
436 return getOptionAs<float, float>(key,
"a single precision floating point value", parse);
446 auto parse = [] (
const std::string & str) {
return std::stod(str); };
447 return getOptionAs<double, double>(key,
"a double precision floating point value", parse);
459 auto parse = [] (
const std::string & str) {
return std::stof(str); };
460 return getOptionAs<float, float>(key,
"a single precision floating point value", parse,
true, defaultValue);
470 auto parse = [] (
const std::string & str) {
return std::stod(str); };
471 return getOptionAs<double, double>(key,
"a double precision floating point value", parse,
true, defaultValue);
482 if (commandLineHasFinalValue == HasFinalValue::No) {
486 if (finalValues.size() <= index) {
489 , ::
toString(
"This parser does not have a final value with index ", index)
493 return finalValues[index];
503 auto parse = [] (
const std::string & str) {
return std::stof(str); };
504 return getFinalValueAs<float>(
"a single precision floating point value", parse, index);
514 auto parse = [] (
const std::string & str) {
return std::stod(str); };
515 return getFinalValueAs<double>(
"a double precision floating point value", parse, index);
524 if (finalValues.size() <= index) {
528 return finalValues[index];
538 auto parse = [] (
const std::string & str) {
return std::stof(str); };
539 return getFinalValueAs<float>(
"a single precision floating point value", parse, index,
true, defaultValue);
549 auto parse = [] (
const std::string & str) {
return std::stod(str); };
550 return getFinalValueAs<double>(
"a double precision floating point value", parse, index,
true, defaultValue);
578 size_t maxSwitchTextWidth = 0;
580 for (
const auto & pair : optionsByKey) {
582 ?
"-" + pair.second.shortSwitch
583 : pair.second.shortSwitch;
586 ? (pair.second.longSwitch.empty() ?
"" :
"--" + pair.second.longSwitch)
587 : pair.second.longSwitch;
589 const std::string switches = shortSw + (longSw.empty() ?
"" :
", " + longSw);
591 if (maxSwitchTextWidth < switches.length()) {
592 maxSwitchTextWidth = switches.length();
597 if (totalWidth < maxSwitchTextWidth + 20) {
598 totalWidth = maxSwitchTextWidth + 20;
601 std::string prefix(indent,
' ');
602 std::string contPrefix(indent + 3 + maxSwitchTextWidth,
' ');
603 std::ostringstream builder;
605 for (
const auto & pair : optionsByKey) {
607 ?
"-" + pair.second.shortSwitch
608 : pair.second.shortSwitch;
611 ? (pair.second.longSwitch.empty() ?
"" :
"--" + pair.second.longSwitch)
612 : pair.second.longSwitch;
614 const auto & option = pair.second;
616 const std::string switches = shortSw + (longSw.empty() ?
"" :
", " + longSw);
618 builder << prefix << std::left << std::setw((
int) maxSwitchTextWidth) << switches <<
" - ";
620 const std::string & docText = option.documentation;
621 size_t charactersWritten = 0;
624 while (charactersWritten < docText.length()) {
625 const size_t charactersRemaining = docText.length() - charactersWritten;
627 if (charactersRemaining <= totalWidth) {
628 builder << (first ?
"" : contPrefix) << docText.substr(charactersWritten) <<
"\n";
629 charactersWritten = docText.length();
631 builder << (first ?
"" : contPrefix) << docText.substr(charactersWritten, totalWidth) <<
"\n";
632 charactersWritten += totalWidth;
639 return builder.str();
644 private:
CommandLineStyle determineStyle(
const std::string & firstArgument,
size_t argCount)
const {
649 if (commandLineHasFinalValue == HasFinalValue::Yes && argCount == 1) {
660 const std::vector<std::string> & args,
664 std::vector<std::string> cleanedArgs;
665 size_t m = ignoreFirst ? 1 : 0;
667 while (m < args.size()) {
668 const std::string & arg = args[m];
671 const size_t first = arg.find(
'=');
672 cleanedArgs.emplace_back(arg.substr(0, first));
673 cleanedArgs.emplace_back(arg.substr(first + 1));
675 cleanedArgs.emplace_back(arg);
681 for (
size_t m = 0; m < (commandLineHasFinalValue == HasFinalValue::Yes ? cleanedArgs.size() - 1 : cleanedArgs.size()); m++) {
683 auto iter = keysBySwitch.find(optionSwitch);
685 if (iter == keysBySwitch.end()) {
689 const auto & key = iter->second;
690 const auto & option = optionsByKey.at(key);
692 if (option.hasValue) {
693 if (commandLineHasFinalValue == HasFinalValue::Yes && cleanedArgs.size() - m < 2) {
695 }
else if (cleanedArgs.size() - m < 1) {
702 parsedValuesByKey[key] =
"";
706 if (commandLineHasFinalValue == HasFinalValue::Yes) {
712 const std::vector<std::string> & args,
714 size_t m = ignoreFirst ? 1 : 0;
716 for (; m < args.size(); m++) {
724 optionSwitch = optionSwitch.substr(2);
726 optionSwitch = optionSwitch.substr(1);
728 if (commandLineHasFinalValue == HasFinalValue::No) {
733 finalValues.push_back(std::move(optionSwitch));
737 auto iter = keysBySwitch.find(optionSwitch);
739 if (iter == keysBySwitch.end()) {
743 const auto & key = iter->second;
744 const auto & option = optionsByKey.at(key);
746 if (option.hasValue) {
747 if (commandLineHasFinalValue == HasFinalValue::Yes && finalValues.empty() && m + 2 == args.size()) {
749 }
else if (m + 1 == args.size()) {
756 parsedValuesByKey[key] =
"";
766 private:
template<
typename T,
typename C> T getOptionAs(KeyT key,
767 const std::string & typeAsString,
768 C parse(
const std::string &),
769 bool orDefault =
false,
770 T defaultValue = T())
const {
771 if (parsedValuesByKey.find(key) == parsedValuesByKey.end()) {
780 , std::string(
"No option with key ") +
toString(key) +
" was supplied on the command line." 784 const std::string str = parsedValuesByKey.at(key);
787 const C value = parse(str);
788 return boost::numeric_cast<T>(value);
789 }
catch (
const std::invalid_argument &) {
794 "Option value of key '" +
toString(key) +
"' is not of type " + typeAsString +
": " 795 + parsedValuesByKey.at(key)
804 "Option value of key '" +
toString(key) +
"' is not in the valid range for " + typeAsString +
": " 805 + parsedValuesByKey.at(key)
815 private:
template<
typename T> T getFinalValueAs(
const std::string & typeAsString,
816 T parse(
const std::string &),
818 bool orDefault =
false,
819 T defaultValue = T())
const {
820 if (commandLineHasFinalValue == HasFinalValue::No) {
828 if (finalValues.size() <= index) {
835 , ::
toString(
"This parser does not have a final value with index ", index)
840 return parse(finalValues[index]);
841 }
catch (
const std::invalid_argument &) {
848 , std::string(
"Final value is not in the valid range for " + typeAsString +
": " + finalValues[index])
853 private:
struct Option {
855 std::string shortSwitch;
856 std::string longSwitch;
858 std::string documentation;
860 Option() : hasValue(
false) {}
863 std::string shortSwitch_,
864 std::string longSwitch_,
866 std::string documentation_)
867 : key(std::move(key_))
868 , shortSwitch(std::move(shortSwitch_))
869 , longSwitch(std::move(longSwitch_))
870 , hasValue(hasValue_)
871 , documentation(std::move(documentation_)) {}
873 Option & operator = (
const Option & copy) =
default;
876 private:
enum class HasFinalValue {
881 private: std::map<std::string, KeyT> keysBySwitch;
882 private: std::map<KeyT, Option> optionsByKey;
883 private: std::map<KeyT, std::string> parsedValuesByKey;
884 private: HasFinalValue commandLineHasFinalValue = HasFinalValue::No;
885 private: std::vector<std::string> finalValues;
890 #endif // COM_BORA_SOFTWARE__BALAU_APPLICATION__COMMAND_LINE The parser will allow either switch-space-value or switch-equals-value.
Thrown when an invalid command line parameter is specified.
Definition: CommandLineExceptions.hpp:38
float getOptionAsFloat(KeyT key) const
Get the specified option value as a float.
Definition: CommandLine.hpp:434
double getOptionAsDoubleOrDefault(KeyT key, double defaultValue) const
Get the specified option value as a double or return the supplied value if there is no such option...
Definition: CommandLine.hpp:469
#define ThrowBalauException(ExceptionClass,...)
Throw a Balau style exception, with implicit file and line number, and optional stacktrace.
Definition: BalauException.hpp:45
unsigned int getOptionAsUnsignedInt(KeyT key) const
Get the specified option value as an unsigned integer value.
Definition: CommandLine.hpp:331
double getOptionAsDouble(KeyT key) const
Get the specified option value as a double.
Definition: CommandLine.hpp:445
static bool contains(const StringT< CharT, T ... > &str, const SubstrT &substring)
Does the first string contain the second string?
Definition: Strings.hpp:174
bool hasOption(KeyT key) const
Does the command line option set have the specified option?
Definition: CommandLine.hpp:248
Balau::U8String< AllocatorT > toString(const BalauException &e)
Base class toString<AllocatorT> function for Balau exceptions.
Definition: BalauException.hpp:122
long long getOptionAsLong(KeyT key) const
Get the specified option value as a signed long long value.
Definition: CommandLine.hpp:342
void parse(int argc, char *argv[], bool ignoreFirst)
Parse the input arguments.
Definition: CommandLine.hpp:174
CommandLine & withFinalValue()
Specify that the command line arguments include one (SEV style) or one or more (SSV style) final stan...
Definition: CommandLine.hpp:148
The root Balau namespace.
Definition: ApplicationConfiguration.hpp:23
int getOptionAsIntOrDefault(KeyT key, int defaultValue) const
Get the specified option value as a signed int, or the specified default if there is no such option...
Definition: CommandLine.hpp:388
short getOptionAsShortOrDefault(KeyT key, short defaultValue) const
Get the specified option value as a signed short, or the specified default if there is no such option...
Definition: CommandLine.hpp:366
CommandLine & withOption(KeyT key, const std::string &shortSwitch, bool hasValue, const std::string &documentation)
Specify an option that has a short style switch.
Definition: CommandLine.hpp:119
Thrown when a requested option value cannot be coerced into the required type.
Definition: CommandLineExceptions.hpp:62
unsigned long long getOptionAsUnsignedLongOrDefault(KeyT key, unsigned long long defaultValue) const
Get the specified option value as an unsigned long long, or the specified default if there is no such...
Definition: CommandLine.hpp:421
std::string getFinalValue(size_t index=0) const
Get the final value with the specified index as a string or throw if no final value is available...
Definition: CommandLine.hpp:481
CommandLine & withOptionalFinalValue()
Specify that the command line arguments include one (SEV style) or one or more (SSV style) final stan...
Definition: CommandLine.hpp:156
CommandLine(CommandLineStyle style_=CommandLineStyle::Detect)
Create a command line parser with the specified style.
Definition: CommandLine.hpp:66
void parse(const std::vector< std::string > &args, bool ignoreFirst)
Parse the input arguments, which are supplied as a vector.
Definition: CommandLine.hpp:219
Switches that have a leading dash '-' character.
std::string getHelpText(size_t indent, size_t totalWidth, CommandLineStyle styleOverride=CommandLineStyle::Detect) const
Get the help text.
Definition: CommandLine.hpp:569
double getFinalValueAsDouble(size_t index=0) const
Get the final value as a double or throw if no final value is available.
Definition: CommandLine.hpp:513
Thrown when an illegal argument is passed to a function or method.
Definition: BalauException.hpp:138
unsigned short getOptionAsUnsignedShort(KeyT key) const
Get the specified option value as an unsigned short value.
Definition: CommandLine.hpp:309
Core includes, typedefs and functions.
unsigned short getOptionAsUnsignedShortOrDefault(KeyT key, unsigned short defaultValue) const
Get the specified option value as an unsigned short, or the specified default if there is no such opt...
Definition: CommandLine.hpp:377
static bool startsWith(const StringT< CharT, T ... > &str, const PrefixT &prefix)
Does the string start with the specified prefix?
Definition: Strings.hpp:46
static std::string_view trim(const std::string_view &input)
Trim whitespace from the beginning and end of the supplied UTF-8 string.
Definition: Strings.hpp:706
size_t getFinalValueCount() const
Get the number of final values available.
Definition: CommandLine.hpp:258
double getFinalValueAsDoubleOrDefault(double defaultValue, size_t index=0) const
Get the final value as a double or return the supplied default if no final value is available...
Definition: CommandLine.hpp:548
std::string getOption(KeyT key) const
Get the specified option value as a UTF-8 string.
Definition: CommandLine.hpp:269
CommandLine & withOption(KeyT key, const std::string &shortSwitch, const std::string &longSwitch, bool hasValue, const std::string &documentation)
Specify an option that has a short style switch and a long style switch.
Definition: CommandLine.hpp:100
A compact command line argument parser.
Definition: CommandLine.hpp:60
CommandLine & withHelpOption(KeyT helpKey, const std::string &shortSwitch, const std::string &longSwitch, const std::string &helpDocumentation)
Specify the help command line short and long switches.
Definition: CommandLine.hpp:135
unsigned int getOptionAsUnsignedIntOrDefault(KeyT key, unsigned int defaultValue) const
Get the specified option value as an unsigned int, or the specified default if there is no such optio...
Definition: CommandLine.hpp:399
Switches that do not require a leading dash.
float getFinalValueAsFloat(size_t index=0) const
Get the final value as a float or throw if no final value is available.
Definition: CommandLine.hpp:502
std::string getFinalValueOrDefault(const std::string &defaultValue, size_t index=0) const
Get the final value as a string or return the supplied default if no final value is available...
Definition: CommandLine.hpp:523
long long getOptionAsLongOrDefault(KeyT key, long long defaultValue) const
Get the specified option value as a signed long long, or the specified default if there is no such op...
Definition: CommandLine.hpp:410
unsigned long long getOptionAsUnsignedLong(KeyT key) const
Get the specified option value as an unsigned long long value.
Definition: CommandLine.hpp:353
int getOptionAsInt(KeyT key) const
Get the specified option value as a signed integer value.
Definition: CommandLine.hpp:320
void parse(int argc, const char *argv[], bool ignoreFirst)
Parse the input arguments.
Definition: CommandLine.hpp:195
short getOptionAsShort(KeyT key) const
Get the specified option value as a signed short value.
Definition: CommandLine.hpp:298
CommandLineStyle
The command line style that the application uses.
Definition: CommandLine.hpp:33
Thrown when there is no option value available and one is required.
Definition: CommandLineExceptions.hpp:46
Thrown when there is no final value available and one is required.
Definition: CommandLineExceptions.hpp:54
float getOptionAsFloatOrDefault(KeyT key, float defaultValue) const
Get the specified option value as a float or return the supplied value if there is no such option...
Definition: CommandLine.hpp:458
Balau::U8String< AllocatorT > toString(LoggingLevel level)
Print the logging level as a UTF-8 string.
Definition: LoggingLevel.hpp:73
std::string getOptionOrDefault(KeyT key, std::string defaultValue) const
Get the specified option value as a string, or the specified default if there is no such option...
Definition: CommandLine.hpp:282
float getFinalValueAsFloatOrDefault(float defaultValue, size_t index=0) const
Get the final value as a float or return the supplied default if no final value is available...
Definition: CommandLine.hpp:537
Balau exceptions for the command line parser.