Working Parser, Mate !

This commit is contained in:
Jerome 2021-12-11 20:21:08 +01:00
parent 1cb3ecd9a0
commit f80b9b9b0e
6 changed files with 237 additions and 68 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
build/*
argParseCpp
argParseTest.exe
*.bat

View file

@ -55,12 +55,29 @@ class ParserParam
/// Returns the help entry string : "-p --param value Parameter "param" with value "value_param" of type integer number"
std::string GetHelpEntryStr() const;
/// Parses the argument(s) given, according to the parameter type. Returns true if the parsing was successful.
bool Parse(const std::string & arg, std::string argval = "");
/// Returns true if the provided name corresponds to either the short name or the long name, even if the parameter is of type "equal"
bool IsThisParamNamed(const std::string & name) const;
/// Returns whether the parameter's value is valid or not
bool IsValid() const;
public:
std::string shortName;
std::string longName;
ParameterType type;
ParameterValueType valueType;
std::string docString;
bool validity; //! indicates whether the parameter's value is valid or not
// Storage for all types of values the parameter can have
bool boolVal;
int intVal;
double doubleVal;
std::string stringVal;
};
/// This class implements a simple argument parser in C++. It can be used to parse a variety of input arguments to programs.
@ -74,13 +91,13 @@ class Parser
void AddParameter(ParserParam param);
/// Parses the arguments passed as parameters.
void Parse(int argc, char **argv);
bool Parse(int argc, char **argv);
/// Parses the arguments passed as a single string.
void Parse(const std::string & argString);
bool Parse(const std::string & argString);
/// Parses the arguments passed as parameters.
void Parse(std::vector<std::string> args);
bool Parse(std::vector<std::string> args);
/// Prints the custom help message if it has been defined, or an automatically constructed one.
void PrintHelp() const;
@ -88,11 +105,11 @@ class Parser
/// Prints the parsed arguments and their associated values.
void PrintParsedArguments() const;
/// Returns the value of the specified argument. A conversion is done between the input text and the output value type.
template<typename T> T GetArgumentValue(const std::string & argName)
{
}
/// Returns the value of the specified argument.
bool GetArgumentValueBool(const std::string & argName);
int GetArgumentValueInt(const std::string & argName);
double GetArgumentValueDouble(const std::string & argName);
std::string const& GetArgumentValueString(const std::string & argName);
protected:
/// Cleans the argument list passed as parameter.
@ -100,12 +117,6 @@ class Parser
protected:
std::vector<ParserParam> parserParams;
std::map<std::string, bool> boolParameters;
std::map<std::string, int> intParameters;
std::map<std::string, double> doubleParameters;
std::map<std::string, std::string> stringParameters;
std::string customHelpMessage;
};

View file

@ -7,4 +7,10 @@
#define PRINT_VAR(v); std::cout << #v << "\t = "; std::cout << (v) << "\n";
#define PRINT_VEC(v); std::cout << #v << "\t =\n"; for(unsigned int i_PRINT_VEC = 0 ; i_PRINT_VEC < (v).size() ; i_PRINT_VEC++) { std::cout << (v)[i_PRINT_VEC] << "\n"; }
/// Returns true if the string str contains the character c.
bool StringContains(const std::string & str, char c);
/// Returns true if the string str starts with beginning
bool StringStartsWith(const std::string & str, const std::string & beginning);
#endif

View file

@ -1,5 +1,7 @@
#include <ArgParseCpp.hpp>
#define ASSERT_MSG(cond, msg); if(!(cond)) { std::cerr << msg << "\n"; exit(1); }
std::vector<std::string> SplitString(const std::string & str, char sep)
{
std::vector<std::string> elems;
@ -60,7 +62,12 @@ ParserParam::ParserParam(const std::string & shortName_, const std::string & lon
longName(longName_),
type(type_),
valueType(valueType_),
docString(docString_)
docString(docString_),
validity(false),
boolVal(false),
intVal(0),
doubleVal(0.),
stringVal("")
{}
const std::string & ParserParam::GenerateDocString()
@ -93,6 +100,56 @@ std::string ParserParam::GetHelpEntryStr() const
return res;
}
bool ParserParam::Parse(const std::string & arg, std::string argval)
{
if(!IsThisParamNamed(arg))
return false;
if(type == ArgParseCpp::StandaloneParam)
{
boolVal = true;
validity = true;
return true;
}
else if(type == ArgParseCpp::SingleValueParam)
{
if(!argval.size())
{
std::cerr << "Error : no value given for parameter \"" << SimpleName() << "\".\n";
return false;
}
}
else if(type == ArgParseCpp::EqualParam)
{
std::vector<std::string> args = SplitString(arg, '=');
if(args.size() != 2)
{
std::cerr << "Error : parameter \"" << SimpleName() << "\" must be written as \"" << shortName << "=value\" or \"" << longName << "=value\".\n";
return false;
}
argval = args[1];
}
// Actually parse the value
if(valueType == ArgParseCpp::Int)
intVal = atoi(argval.c_str());
else if(valueType == ArgParseCpp::Double)
doubleVal = atof(argval.c_str());
else if(valueType == ArgParseCpp::String)
stringVal = argval;
validity = true;
return true;
}
bool ParserParam::IsThisParamNamed(const std::string & name) const
{
return name == shortName || name == longName || StringStartsWith(name, shortName) || StringStartsWith(name, longName);
}
bool ParserParam::IsValid() const { return validity; }
// ------------------- ArgParseCpp::Parser -------------------
Parser::Parser() {}
@ -103,17 +160,17 @@ void Parser::AddParameter(ParserParam param)
parserParams.push_back(param);
}
void Parser::Parse(int argc, char **argv)
bool Parser::Parse(int argc, char **argv)
{
std::vector<std::string> args;
for(int i = 0 ; i < argc ; i++)
args.push_back(argv[i]);
Parse(args);
return Parse(args);
}
void Parser::Parse(const std::string & argString) { Parse(SplitString(argString, ' ')); }
bool Parser::Parse(const std::string & argString) { return Parse(SplitString(argString, ' ')); }
void Parser::Parse(std::vector<std::string> args)
bool Parser::Parse(std::vector<std::string> args)
{
CleanArgs(args);
@ -121,57 +178,85 @@ void Parser::Parse(std::vector<std::string> args)
{
std::cerr << "Error : no arguments passed to the program.\n";
PrintHelp();
return;// exit(1);
return false;
}
else
{
// DEBUG
PRINT_VAR(args.size());
PRINT_VEC(args);
// Prepare all the boolean arguments
for(ParserParam const& param : parserParams) // loop over all parameters
if(param.type == ArgParseCpp::StandaloneParam) // if the parameter is a boolean type
boolParameters[param.SimpleName()] = false;
for(std::string const& arg : args)
for(unsigned int iArg = 0 ; iArg < args.size() ; iArg++) // loop over all arguments
{
std::string arg = args[iArg];
if(arg == "-h" || arg == "--help")
{
PrintHelp();
return;// exit(1);
return false;
}
for(unsigned int iParam = 0 ; iParam < parserParams.size() ; iParam++) // loop over all parameters
bool argumentParsed = false;
for(ParserParam & param : parserParams) // loop over all parameters
{
ParserParam const& param = parserParams[iParam];
PRINT_VAR(arg);
PRINT_VAR(param.shortName);
PRINT_VAR(param.longName);
std::cout << "----\n";
if(arg == param.shortName || arg == param.longName) // if the argument corresponds to this parameter
if(iArg+1 < args.size())
{
if(param.type == ArgParseCpp::StandaloneParam)
boolParameters[param.SimpleName()] = true;
else if(param.type == ArgParseCpp::SingleValueParam)
{
if(iParam+1 >= parserParams.size())
{
std::cerr << "Error : parameter " << arg << " must be followed by a single value.";
return;
}
if(param.valueType == ArgParseCpp::Int)
intParameters[param.SimpleName()] = atoi(parserParams[++iParam]);// read next parameter as the value of this argument, and skip the next iteration, as the next argument has already been processed
if(param.valueType == ArgParseCpp::Double)
doubleParameters[param.SimpleName()] = strtod(parserParams[++iParam]);// read next parameter as the value of this argument, and skip the next iteration, as the next argument has already been processed
if(param.valueType == ArgParseCpp::String)
stringParameters[param.SimpleName()] = parserParams[++iParam];// read next parameter as the value of this argument, and skip the next iteration, as the next argument has already been processed
}
bool argumentParsedWithThisParam = param.Parse(arg, args[iArg+1]);
argumentParsed |= argumentParsedWithThisParam;
if(argumentParsedWithThisParam && param.type == ArgParseCpp::SingleValueParam)
iArg++; // skip next argument, as it has already been
}
else
argumentParsed |= param.Parse(arg);
if(argumentParsed)
break;
}
}
}
return true;
}
bool Parser::GetArgumentValueBool(const std::string & argName)
{
for(ParserParam const& param : parserParams)
if(param.IsThisParamNamed(argName) || argName == param.SimpleName())
{
ASSERT_MSG(param.valueType == ArgParseCpp::Bool, "Error : parameter \"" << param.SimpleName() << "\" is not of type bool.");
return param.boolVal;
}
std::cerr << "Error : parameter \"" << argName << "\" is not defined.";
exit(1);
}
int Parser::GetArgumentValueInt(const std::string & argName)
{
for(ParserParam const& param : parserParams)
if(param.IsThisParamNamed(argName) || argName == param.SimpleName())
{
ASSERT_MSG(param.valueType == ArgParseCpp::Int, "Error : parameter \"" << param.SimpleName() << "\" is not of type int.");
return param.intVal;
}
std::cerr << "Error : parameter \"" << argName << "\" is not defined.";
exit(1);
}
double Parser::GetArgumentValueDouble(const std::string & argName)
{
for(ParserParam const& param : parserParams)
if(param.IsThisParamNamed(argName) || argName == param.SimpleName())
{
ASSERT_MSG(param.valueType == ArgParseCpp::Double, "Error : parameter \"" << param.SimpleName() << "\" is not of type double.");
return param.doubleVal;
}
std::cerr << "Error : parameter \"" << argName << "\" is not defined.";
exit(1);
}
std::string const& Parser::GetArgumentValueString(const std::string & argName)
{
for(ParserParam const& param : parserParams)
if(param.IsThisParamNamed(argName) || argName == param.SimpleName())
{
ASSERT_MSG(param.valueType == ArgParseCpp::String, "Error : parameter \"" << param.SimpleName() << "\" is not of type string.");
return param.stringVal;
}
std::cerr << "Error : parameter \"" << argName << "\" is not defined.";
exit(1);
}
void Parser::PrintHelp() const
@ -191,18 +276,17 @@ void Parser::PrintHelp() const
void Parser::PrintParsedArguments() const
{
std::cout << "\nBoolean parameters\n------------------\n";
for(auto const& arg : boolParameters)
std::cout << arg.first << "\t= " << arg.second << "\n";
std::cout << "\nInteger parameters\n------------------\n";
for(auto const& arg : intParameters)
std::cout << arg.first << "\t= " << arg.second << "\n";
std::cout << "\nFloating-point parameters\n-------------------------\n";
for(auto const& arg : doubleParameters)
std::cout << arg.first << "\t= " << arg.second << "\n";
std::cout << "\nString parameters\n------------------\n";
for(auto const& arg : stringParameters)
std::cout << arg.first << "\t= " << arg.second << "\n";
for(ParserParam const& arg : parserParams)
{
if(arg.valueType == ArgParseCpp::Bool)
std::cout << arg.SimpleName() << "\t= " << arg.boolVal << "\n";
if(arg.valueType == ArgParseCpp::Int)
std::cout << arg.SimpleName() << "\t= " << arg.intVal << "\n";
if(arg.valueType == ArgParseCpp::Double)
std::cout << arg.SimpleName() << "\t= " << arg.doubleVal << "\n";
if(arg.valueType == ArgParseCpp::String)
std::cout << arg.SimpleName() << "\t= " << arg.stringVal << "\n";
}
}
void Parser::CleanArgs(std::vector<std::string> & args) const

View file

@ -39,12 +39,14 @@ int main(int argc, char *argv[])
if(0)
{// sanitize the input arguments and display help whenever -h or --help is seen
std::string argString = "programName -h blabla hehe hoho lalaland";
PRINT_VAR(argString);
Parser parser;
parser.Parse(argString);
}
if(0)
{// parse some boolean arguments
std::string argString = "programName -v --all";
PRINT_VAR(argString);
Parser parser;
parser.AddParameter(ArgParseCpp::ParserParam("-v", "--verbose", ArgParseCpp::StandaloneParam, ArgParseCpp::Bool, "Makes the program more verbose."));
parser.AddParameter(ArgParseCpp::ParserParam("-a", "--all", ArgParseCpp::StandaloneParam));
@ -54,9 +56,10 @@ int main(int argc, char *argv[])
parser.Parse(argString);
parser.PrintParsedArguments();
}
// if(0)
if(0)
{// parse single value arguments
std::string argString = "programName -a 5 -b 12.654 -s blabla_mon_negro hehe";
PRINT_VAR(argString);
Parser parser;
parser.AddParameter(ArgParseCpp::ParserParam("-a", "--all", ArgParseCpp::SingleValueParam, ArgParseCpp::Int));
parser.AddParameter(ArgParseCpp::ParserParam("-b", "--brief", ArgParseCpp::SingleValueParam, ArgParseCpp::Double));
@ -64,6 +67,48 @@ int main(int argc, char *argv[])
parser.PrintHelp();
parser.Parse(argString);
parser.PrintParsedArguments();
PRINT_VAR(parser.GetArgumentValueInt("-a"));
PRINT_VAR(parser.GetArgumentValueInt("--all"));
PRINT_VAR(parser.GetArgumentValueDouble("brief"));
PRINT_VAR(parser.GetArgumentValueString("s"));
// PRINT_VAR(parser.GetArgumentValueInt("brief"));// wrong type = exit program
}
if(0)
{// parse equal-type arguments
std::string argString = "programName -a=5 -b=12.654 -s=blabla_mon_negro sfdg";
PRINT_VAR(argString);
Parser parser;
parser.AddParameter(ArgParseCpp::ParserParam("-a", "--all", ArgParseCpp::EqualParam, ArgParseCpp::Int));
parser.AddParameter(ArgParseCpp::ParserParam("-b", "--brief", ArgParseCpp::EqualParam, ArgParseCpp::Double));
parser.AddParameter(ArgParseCpp::ParserParam("-s", "", ArgParseCpp::EqualParam, ArgParseCpp::String));
parser.PrintHelp();
parser.Parse(argString);
parser.PrintParsedArguments();
PRINT_VAR(parser.GetArgumentValueInt("-a"));
PRINT_VAR(parser.GetArgumentValueInt("--all"));
PRINT_VAR(parser.GetArgumentValueDouble("brief"));
PRINT_VAR(parser.GetArgumentValueString("s"));
}
// if(0)
{// parse all types of arguments
std::string argString = "programName -v -a 5 -b=12.654 -s blabla_mon_negro sfdg";
PRINT_VAR(argString);
Parser parser;
parser.AddParameter(ArgParseCpp::ParserParam("-v", "--verbose", ArgParseCpp::StandaloneParam));
parser.AddParameter(ArgParseCpp::ParserParam("-i", "", ArgParseCpp::StandaloneParam));
parser.AddParameter(ArgParseCpp::ParserParam("-a", "--all", ArgParseCpp::SingleValueParam, ArgParseCpp::Int));
parser.AddParameter(ArgParseCpp::ParserParam("-b", "--brief", ArgParseCpp::EqualParam, ArgParseCpp::Double));
parser.AddParameter(ArgParseCpp::ParserParam("-s", "", ArgParseCpp::SingleValueParam, ArgParseCpp::String));
parser.PrintHelp();
parser.Parse(argString);
parser.PrintParsedArguments();
PRINT_VAR(parser.GetArgumentValueInt("-a"));
PRINT_VAR(parser.GetArgumentValueInt("--all"));
PRINT_VAR(parser.GetArgumentValueDouble("brief"));
PRINT_VAR(parser.GetArgumentValueString("s"));
PRINT_VAR(parser.GetArgumentValueBool("verbose"));
PRINT_VAR(parser.GetArgumentValueBool("i"));
}
}

View file

@ -1 +1,20 @@
#include <utils.hpp>
bool StringContains(const std::string & str, char c)
{
for(unsigned int i = 0 ; i < str.size() ; i++)
if(str[i] == c)
return true;
return false;
}
bool StringStartsWith(const std::string & str, const std::string & beginning)
{
if(str.size() < beginning.size() || !str.size() || !beginning.size())
return false;
for(unsigned int i = 0 ; i < beginning.size() ; i++)
if(beginning[i] != str[i])
return false;
return true;
}