Browse Source

Util: Add argument parsing to ArgParser

master
Riyyi 3 years ago
parent
commit
67fd31a746
  1. 98
      src/util/argparser.cpp
  2. 18
      src/util/argparser.h

98
src/util/argparser.cpp

@ -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

18
src/util/argparser.h

@ -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;
}; };

Loading…
Cancel
Save