Util: Add argument parsing to ArgParser
This commit is contained in:
+88
-10
@@ -1,7 +1,8 @@
|
|||||||
#include <algorithm> // find_if
|
#include <algorithm> // find_if
|
||||||
#include <cstdio> // printf
|
#include <cstddef> // size_t
|
||||||
#include <limits> // numeric_limits
|
#include <cstdio> // printf
|
||||||
#include <string> // stod, stoi, stoul
|
#include <limits> // numeric_limits
|
||||||
|
#include <string> // stod, stoi, stoul
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include "util/argparser.h"
|
#include "util/argparser.h"
|
||||||
@@ -187,12 +188,34 @@ bool ArgParser::parseLongOption(std::string_view option, std::string_view next)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ArgParser::parseArgument(std::string_view argument)
|
||||||
|
{
|
||||||
|
// No handler for argument
|
||||||
|
if (m_argumentIndex >= m_arguments.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Argument& currentArgument = m_arguments.at(m_argumentIndex);
|
||||||
|
bool result = currentArgument.acceptValue(argument.data());
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
currentArgument.addedValues++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentArgument.addedValues >= currentArgument.maxValues) {
|
||||||
|
m_argumentIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool ArgParser::parse(int argc, const char* argv[])
|
bool ArgParser::parse(int argc, const char* argv[])
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
// Skip program name argument
|
// Set looping indices
|
||||||
m_optionIndex = 1;
|
m_optionIndex = 1;
|
||||||
|
m_argumentIndex = 0;
|
||||||
|
|
||||||
// By default parse all '-' prefixed parameters as options
|
// By default parse all '-' prefixed parameters as options
|
||||||
m_nonOptionMode = false;
|
m_nonOptionMode = false;
|
||||||
@@ -202,12 +225,12 @@ bool ArgParser::parse(int argc, const char* argv[])
|
|||||||
|
|
||||||
std::string_view argument;
|
std::string_view argument;
|
||||||
std::string_view next;
|
std::string_view next;
|
||||||
for (; m_optionIndex < argc; ++m_optionIndex) {
|
for (; m_optionIndex < (size_t)argc; ++m_optionIndex) {
|
||||||
printf("argv[%d]: %s\n", m_optionIndex, argv[m_optionIndex]);
|
printf("argv[%zu]: %s\n", m_optionIndex, argv[m_optionIndex]);
|
||||||
|
|
||||||
// Get the current and next parameter
|
// Get the current and next parameter
|
||||||
argument = argv[m_optionIndex];
|
argument = argv[m_optionIndex];
|
||||||
if (m_optionIndex + 1 < argc && argv[m_optionIndex + 1][0] != '-') {
|
if (m_optionIndex + 1 < (size_t)argc && argv[m_optionIndex + 1][0] != '-') {
|
||||||
next = argv[m_optionIndex + 1];
|
next = argv[m_optionIndex + 1];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -239,7 +262,9 @@ bool ArgParser::parse(int argc, const char* argv[])
|
|||||||
if (m_stopParsingOnFirstNonOption) {
|
if (m_stopParsingOnFirstNonOption) {
|
||||||
m_nonOptionMode = true;
|
m_nonOptionMode = true;
|
||||||
}
|
}
|
||||||
printf("-> argu: '%s'", argument.data());
|
if (!parseArgument(argument)) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_exitOnFirstError && !result) {
|
if (m_exitOnFirstError && !result) {
|
||||||
@@ -247,9 +272,20 @@ bool ArgParser::parse(int argc, const char* argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check any leftover arguments for required
|
||||||
|
for (; m_argumentIndex < m_arguments.size(); ++m_argumentIndex) {
|
||||||
|
Argument& currentArgument = m_arguments.at(m_argumentIndex);
|
||||||
|
if (currentArgument.minValues > currentArgument.addedValues) {
|
||||||
|
result = false;
|
||||||
|
// TODO: decide if and what to print here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
void ArgParser::addOption(Option&& option)
|
void ArgParser::addOption(Option&& option)
|
||||||
{
|
{
|
||||||
m_options.push_back(option);
|
m_options.push_back(option);
|
||||||
@@ -363,8 +399,7 @@ void ArgParser::addOption(unsigned int& value, char shortName, const char* longN
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (convert <= std::numeric_limits<unsigned int>::max())
|
if (convert <= std::numeric_limits<unsigned int>::max()) {
|
||||||
{
|
|
||||||
value = static_cast<unsigned int>(convert);
|
value = static_cast<unsigned int>(convert);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -414,4 +449,47 @@ void ArgParser::addOption(std::vector<std::string>& values, char shortName, cons
|
|||||||
addOption(std::move(option));
|
addOption(std::move(option));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------
|
||||||
|
|
||||||
|
void ArgParser::addArgument(Argument&& argument)
|
||||||
|
{
|
||||||
|
m_arguments.push_back(argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArgParser::addArgument(std::string& value, const char* name, const char* usageString, const char* manString, Required required)
|
||||||
|
{
|
||||||
|
size_t minValues = required == Required::Yes ? 1 : 0;
|
||||||
|
Argument argument {
|
||||||
|
name,
|
||||||
|
usageString,
|
||||||
|
manString,
|
||||||
|
minValues,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
[&value](const char* a) -> bool {
|
||||||
|
value = a;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addArgument(std::move(argument));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArgParser::addArgument(std::vector<std::string>& values, const char* name, const char* usageString, const char* manString, Required required)
|
||||||
|
{
|
||||||
|
size_t minValues = required == Required::Yes ? 1 : 0;
|
||||||
|
Argument argument {
|
||||||
|
name,
|
||||||
|
usageString,
|
||||||
|
manString,
|
||||||
|
minValues,
|
||||||
|
values.max_size(),
|
||||||
|
0,
|
||||||
|
[&values](const char* a) -> bool {
|
||||||
|
values.push_back(a);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addArgument(std::move(argument));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Util
|
} // namespace Util
|
||||||
|
|||||||
+16
-2
@@ -1,6 +1,7 @@
|
|||||||
#ifndef ARG_PARSER_H
|
#ifndef ARG_PARSER_H
|
||||||
#define ARG_PARSER_H
|
#define ARG_PARSER_H
|
||||||
|
|
||||||
|
#include <cstddef> // size_t
|
||||||
#include <functional> // function
|
#include <functional> // function
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@@ -40,6 +41,13 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Argument {
|
struct Argument {
|
||||||
|
const char* name { nullptr };
|
||||||
|
const char* usageString { nullptr };
|
||||||
|
const char* manString { nullptr };
|
||||||
|
size_t minValues { 0 };
|
||||||
|
size_t maxValues { 1 };
|
||||||
|
size_t addedValues { 0 };
|
||||||
|
std::function<bool(const char*)> acceptValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool parse(int argc, const char* argv[]);
|
bool parse(int argc, const char* argv[]);
|
||||||
@@ -54,6 +62,10 @@ public:
|
|||||||
void addOption(double& value, char shortName, const char* longName, const char* usageString, const char* manString, const char* argumentName = "", Required requiresArgument = Required::No);
|
void addOption(double& value, char shortName, const char* longName, const char* usageString, const char* manString, const char* argumentName = "", Required requiresArgument = Required::No);
|
||||||
void addOption(std::vector<std::string>& values, char shortName, const char* longName, const char* usageString, const char* manString, const char* argumentName = "", Required requiresArgument = Required::No);
|
void addOption(std::vector<std::string>& values, char shortName, const char* longName, const char* usageString, const char* manString, const char* argumentName = "", Required requiresArgument = Required::No);
|
||||||
|
|
||||||
|
void addArgument(Argument&& argument);
|
||||||
|
void addArgument(std::string& value, const char* name, const char* usageString, const char* manString, Required required = Required::No);
|
||||||
|
void addArgument(std::vector<std::string>& values, const char* name, const char* usageString, const char* manString, Required required = Required::No);
|
||||||
|
|
||||||
void setErrorReporting(bool state) { m_errorReporting = state; }
|
void setErrorReporting(bool state) { m_errorReporting = state; }
|
||||||
void setExitOnFirstError(bool state) { m_exitOnFirstError = state; }
|
void setExitOnFirstError(bool state) { m_exitOnFirstError = state; }
|
||||||
void setStopParsingOnFirstNonOption(bool state) { m_stopParsingOnFirstNonOption = state; }
|
void setStopParsingOnFirstNonOption(bool state) { m_stopParsingOnFirstNonOption = state; }
|
||||||
@@ -63,15 +75,17 @@ private:
|
|||||||
void printOptionError(const char* name, Error error, bool longName = true);
|
void printOptionError(const char* name, Error error, bool longName = true);
|
||||||
bool parseShortOption(std::string_view option, std::string_view next);
|
bool parseShortOption(std::string_view option, std::string_view next);
|
||||||
bool parseLongOption(std::string_view option, std::string_view next);
|
bool parseLongOption(std::string_view option, std::string_view next);
|
||||||
|
bool parseArgument(std::string_view argument);
|
||||||
|
|
||||||
bool m_errorReporting { true };
|
bool m_errorReporting { true };
|
||||||
bool m_exitOnFirstError { true };
|
bool m_exitOnFirstError { true };
|
||||||
bool m_stopParsingOnFirstNonOption { false };
|
bool m_stopParsingOnFirstNonOption { false };
|
||||||
|
|
||||||
int m_optionIndex { 1 };
|
size_t m_optionIndex { 1 };
|
||||||
|
size_t m_argumentIndex { 0 };
|
||||||
bool m_nonOptionMode { false };
|
bool m_nonOptionMode { false };
|
||||||
|
|
||||||
const char* m_name;
|
const char* m_name { nullptr };
|
||||||
std::vector<Option> m_options;
|
std::vector<Option> m_options;
|
||||||
std::vector<Argument> m_arguments;
|
std::vector<Argument> m_arguments;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user