Help string generation done.
Boolean parsing done.
This commit is contained in:
commit
1cb3ecd9a0
6 changed files with 494 additions and 0 deletions
72
Makefile
Normal file
72
Makefile
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
CXX ?= g++
|
||||
|
||||
# path #
|
||||
SRC_PATH = src
|
||||
BUILD_PATH = build
|
||||
BIN_PATH = $(BUILD_PATH)/bin
|
||||
|
||||
# executable #
|
||||
BIN_NAME = argParseCpp
|
||||
|
||||
# extensions #
|
||||
SRC_EXT = cpp
|
||||
|
||||
# code lists #
|
||||
# Find all source files in the source directory, sorted by
|
||||
# most recently modified
|
||||
SOURCES = $(shell find $(SRC_PATH) -name '*.$(SRC_EXT)' | sort -k 1nr | cut -f2-)
|
||||
# Set the object file names, with the source directory stripped
|
||||
# from the path, and the build path prepended in its place
|
||||
OBJECTS = $(SOURCES:$(SRC_PATH)/%.$(SRC_EXT)=$(BUILD_PATH)/%.o)
|
||||
# Set the dependency files that will be used to add header dependencies
|
||||
DEPS = $(OBJECTS:.o=.d)
|
||||
|
||||
# flags #
|
||||
COMPILE_FLAGS = -std=c++11 -Wall -Wextra -g
|
||||
INCLUDES = -I include/ -I /usr/local/include
|
||||
# Space-separated pkg-config libraries used by this project
|
||||
LIBS =
|
||||
|
||||
.PHONY: default_target
|
||||
default_target: release
|
||||
|
||||
.PHONY: release
|
||||
release: export CXXFLAGS := $(CXXFLAGS) $(COMPILE_FLAGS)
|
||||
release: dirs
|
||||
@$(MAKE) all
|
||||
|
||||
.PHONY: dirs
|
||||
dirs:
|
||||
@echo "Creating directories"
|
||||
@mkdir -p $(dir $(OBJECTS))
|
||||
@mkdir -p $(BIN_PATH)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "Deleting $(BIN_NAME) symlink"
|
||||
@$(RM) $(BIN_NAME)
|
||||
@echo "Deleting directories"
|
||||
@$(RM) -r $(BUILD_PATH)
|
||||
@$(RM) -r $(BIN_PATH)
|
||||
|
||||
# checks the executable and symlinks to the output
|
||||
.PHONY: all
|
||||
all: $(BIN_PATH)/$(BIN_NAME)
|
||||
@echo "Making symlink: $(BIN_NAME) -> $<"
|
||||
@$(RM) $(BIN_NAME)
|
||||
@ln -s $(BIN_PATH)/$(BIN_NAME) $(BIN_NAME)
|
||||
|
||||
# Creation of the executable
|
||||
$(BIN_PATH)/$(BIN_NAME): $(OBJECTS)
|
||||
@echo "Linking: $@"
|
||||
$(CXX) $(OBJECTS) -o $@ ${LIBS}
|
||||
|
||||
# Add dependency files, if they exist
|
||||
-include $(DEPS)
|
||||
|
||||
# Source file rules
|
||||
# After the first compilation they will be joined with the rules from the
|
||||
# dependency files to provide header dependencies
|
||||
$(BUILD_PATH)/%.o: $(SRC_PATH)/%.$(SRC_EXT)
|
||||
@echo "Compiling: $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) -MP -MMD -c $< -o $@
|
||||
114
include/ArgParseCpp.hpp
Normal file
114
include/ArgParseCpp.hpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#ifndef DEF_ArgParseCpp
|
||||
#define DEF_ArgParseCpp
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <utils.hpp>
|
||||
|
||||
std::vector<std::string> SplitString(const std::string & str, char sep);
|
||||
std::string RemovePrefixDashes(const std::string & str);
|
||||
|
||||
namespace ArgParseCpp
|
||||
{
|
||||
|
||||
/// Used to describe the parser parameter type.
|
||||
enum ParameterType
|
||||
{
|
||||
StandaloneParam, // Represents all parameters such as "--param"
|
||||
SingleValueParam, // Represents all parameters such as "--param value"
|
||||
EqualParam // Represents all parameters such as "--param=value"
|
||||
// ListParam // Represents all parameters such as "--param=value1,value2,..,valueN"
|
||||
};
|
||||
|
||||
/// Used to describe the parser parameter value type.
|
||||
enum ParameterValueType
|
||||
{
|
||||
Bool,
|
||||
Int,
|
||||
Double,
|
||||
String
|
||||
};
|
||||
|
||||
/// Converts a ParameterValueType into a string for display.
|
||||
std::string ParameterValueType2Str(const ParameterValueType & paramValueType);
|
||||
|
||||
/// This class defines an argument parser parameter, with its short and long name, its type, its value type, and its docstring.
|
||||
class ParserParam
|
||||
{
|
||||
public:
|
||||
/// Builds a new parser param object with the specified parameters.
|
||||
ParserParam(const std::string & shortName_, const std::string & longName_, ParameterType type_, ParameterValueType valueType_ = ArgParseCpp::Bool, const std::string & docString_ = "");
|
||||
|
||||
/// Generates automatically a doc string based on the parameter type and value type, and repaces the current doc string with the newly generated one.
|
||||
const std::string & GenerateDocString();
|
||||
|
||||
/// If no doc string has been specified, it is automatically generated.
|
||||
void AutoGenerateDocString();
|
||||
|
||||
/// Returns either the full name without prefix dashes, or the short name without prefix dashes.
|
||||
std::string SimpleName() const;
|
||||
|
||||
/// Returns the help entry string : "-p --param value Parameter "param" with value "value_param" of type integer number"
|
||||
std::string GetHelpEntryStr() const;
|
||||
|
||||
public:
|
||||
std::string shortName;
|
||||
std::string longName;
|
||||
ParameterType type;
|
||||
ParameterValueType valueType;
|
||||
std::string docString;
|
||||
};
|
||||
|
||||
/// This class implements a simple argument parser in C++. It can be used to parse a variety of input arguments to programs.
|
||||
class Parser
|
||||
{
|
||||
public:
|
||||
/// Creates an empty parser.
|
||||
Parser();
|
||||
|
||||
/// Adds a parameter to be parsed.
|
||||
void AddParameter(ParserParam param);
|
||||
|
||||
/// Parses the arguments passed as parameters.
|
||||
void Parse(int argc, char **argv);
|
||||
|
||||
/// Parses the arguments passed as a single string.
|
||||
void Parse(const std::string & argString);
|
||||
|
||||
/// Parses the arguments passed as parameters.
|
||||
void Parse(std::vector<std::string> args);
|
||||
|
||||
/// Prints the custom help message if it has been defined, or an automatically constructed one.
|
||||
void PrintHelp() const;
|
||||
|
||||
/// 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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Cleans the argument list passed as parameter.
|
||||
void CleanArgs(std::vector<std::string> & args) const;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace ArgParseCpp
|
||||
|
||||
#endif
|
||||
10
include/utils.hpp
Normal file
10
include/utils.hpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef DEF_Utils
|
||||
#define DEF_Utils
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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"; }
|
||||
|
||||
#endif
|
||||
226
src/ArgParseCpp.cpp
Normal file
226
src/ArgParseCpp.cpp
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
#include <ArgParseCpp.hpp>
|
||||
|
||||
std::vector<std::string> SplitString(const std::string & str, char sep)
|
||||
{
|
||||
std::vector<std::string> elems;
|
||||
std::string elem;
|
||||
for(unsigned int i = 0 ; i < str.size() ; i++)
|
||||
{
|
||||
if(str[i] != sep)
|
||||
elem += str[i];
|
||||
else
|
||||
{
|
||||
elems.push_back(elem);
|
||||
elem = "";
|
||||
}
|
||||
}
|
||||
if(elem.size())
|
||||
elems.push_back(elem);
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::string RemovePrefixDashes(const std::string & str)
|
||||
{
|
||||
std::string res;
|
||||
bool inPrefix = true;
|
||||
for(unsigned int i = 0 ; i < str.size() ; i++)
|
||||
{
|
||||
if(str[i] == '-')
|
||||
continue;
|
||||
else
|
||||
inPrefix = false;
|
||||
if(!inPrefix)
|
||||
res += str[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// ------------------- ArgParseCpp -------------------
|
||||
|
||||
namespace ArgParseCpp
|
||||
{
|
||||
|
||||
std::string ParameterValueType2Str(const ParameterValueType & paramValueType)
|
||||
{
|
||||
if(paramValueType == ArgParseCpp::Bool)
|
||||
return "bool";
|
||||
else if(paramValueType == ArgParseCpp::Int)
|
||||
return "integer number";
|
||||
else if(paramValueType == ArgParseCpp::Double)
|
||||
return "floating-point number";
|
||||
else if(paramValueType == ArgParseCpp::String)
|
||||
return "string";
|
||||
return "";
|
||||
}
|
||||
|
||||
// ------------------- ArgParseCpp::ParserParam -------------------
|
||||
|
||||
ParserParam::ParserParam(const std::string & shortName_, const std::string & longName_, ParameterType type_, ParameterValueType valueType_, const std::string & docString_)
|
||||
: shortName(shortName_),
|
||||
longName(longName_),
|
||||
type(type_),
|
||||
valueType(valueType_),
|
||||
docString(docString_)
|
||||
{}
|
||||
|
||||
const std::string & ParserParam::GenerateDocString()
|
||||
{
|
||||
if(type == ArgParseCpp::StandaloneParam)
|
||||
docString = "Activates the option \"" + SimpleName() + "\" when present.";
|
||||
else if(type == ArgParseCpp::SingleValueParam || type == ArgParseCpp::EqualParam)
|
||||
docString = "Sets the parameter \"" + SimpleName() + "\" at the value \"value_" + SimpleName() + "\" of type " + ParameterValueType2Str(valueType) + ".";
|
||||
|
||||
return docString;
|
||||
}
|
||||
|
||||
void ParserParam::AutoGenerateDocString()
|
||||
{
|
||||
if(!docString.size())
|
||||
GenerateDocString();
|
||||
}
|
||||
|
||||
std::string ParserParam::SimpleName() const { return RemovePrefixDashes((longName.size()) ? longName : shortName); }
|
||||
|
||||
std::string ParserParam::GetHelpEntryStr() const
|
||||
{
|
||||
std::string res;
|
||||
if(type == ArgParseCpp::StandaloneParam)
|
||||
res = " " + shortName + "\t" + longName + "\t" + docString + "\n";
|
||||
else if(type == ArgParseCpp::SingleValueParam)
|
||||
res = " " + shortName + "\t" + longName + " value_" + SimpleName() + "\t" + docString + "\n";
|
||||
else if(type == ArgParseCpp::EqualParam)
|
||||
res = " " + shortName + "\t" + longName + "=value_" + SimpleName() + "\t" + docString + "\n";
|
||||
return res;
|
||||
}
|
||||
|
||||
// ------------------- ArgParseCpp::Parser -------------------
|
||||
|
||||
Parser::Parser() {}
|
||||
|
||||
void Parser::AddParameter(ParserParam param)
|
||||
{
|
||||
param.AutoGenerateDocString();
|
||||
parserParams.push_back(param);
|
||||
}
|
||||
|
||||
void 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);
|
||||
}
|
||||
|
||||
void Parser::Parse(const std::string & argString) { Parse(SplitString(argString, ' ')); }
|
||||
|
||||
void Parser::Parse(std::vector<std::string> args)
|
||||
{
|
||||
CleanArgs(args);
|
||||
|
||||
if(args.size() <= 1)
|
||||
{
|
||||
std::cerr << "Error : no arguments passed to the program.\n";
|
||||
PrintHelp();
|
||||
return;// exit(1);
|
||||
}
|
||||
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)
|
||||
{
|
||||
if(arg == "-h" || arg == "--help")
|
||||
{
|
||||
PrintHelp();
|
||||
return;// exit(1);
|
||||
}
|
||||
|
||||
for(unsigned int iParam = 0 ; iParam < parserParams.size() ; iParam++) // 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(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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::PrintHelp() const
|
||||
{
|
||||
if(customHelpMessage.size())
|
||||
std::cout << customHelpMessage << "\n";
|
||||
else
|
||||
{
|
||||
// Generate a help message
|
||||
std::cout << "Usage : \n";
|
||||
std::cout << " -h, -help\t\tPrints this help message and exits.\n";
|
||||
|
||||
for(ParserParam param : parserParams)
|
||||
std::cout << param.GetHelpEntryStr();
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
void Parser::CleanArgs(std::vector<std::string> & args) const
|
||||
{
|
||||
for(std::vector<std::string>::iterator it = args.end()-1 ; it != args.begin() ; --it)
|
||||
{
|
||||
if((*it).size() == 0) // remove empty arguments
|
||||
args.erase(it);
|
||||
else // clean individual arguments
|
||||
{
|
||||
char c = (*it)[(*it).size()-1];
|
||||
while(c == ' ' || c == '\t' || c == '\n')
|
||||
{
|
||||
(*it).erase(*((*it).end()));
|
||||
c = (*it)[(*it).size()-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ArgParseCpp
|
||||
71
src/test_ArgParseCpp.cpp
Normal file
71
src/test_ArgParseCpp.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#include <iostream>
|
||||
#include <ArgParseCpp.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
using ArgListT = std::vector<std::string>;
|
||||
using ArgParseCpp::Parser;
|
||||
|
||||
template<typename T> std::vector<T> & operator<<(std::vector<T> &vec, const T & val)
|
||||
{
|
||||
vec.push_back(val);
|
||||
return vec;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Test the parser on the arguments provided in main()
|
||||
if(argc > 1)
|
||||
{
|
||||
Parser parser;
|
||||
parser.Parse(argc, argv);
|
||||
}
|
||||
|
||||
// Test the parser in various predefined scenarios
|
||||
else
|
||||
{
|
||||
if(0)
|
||||
{// automatic help message
|
||||
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, ArgParseCpp::Bool, "Does all the things."));
|
||||
parser.AddParameter(ArgParseCpp::ParserParam("-n", "--nope", ArgParseCpp::StandaloneParam));
|
||||
parser.AddParameter(ArgParseCpp::ParserParam("-d", "--decimate", ArgParseCpp::SingleValueParam, ArgParseCpp::Int, "Decimates the signal by a factor d."));
|
||||
parser.AddParameter(ArgParseCpp::ParserParam("-b", "--babar", ArgParseCpp::SingleValueParam, ArgParseCpp::Int));
|
||||
parser.AddParameter(ArgParseCpp::ParserParam("-c", "", ArgParseCpp::SingleValueParam, ArgParseCpp::Double));
|
||||
parser.AddParameter(ArgParseCpp::ParserParam("-o", "", ArgParseCpp::SingleValueParam, ArgParseCpp::String));
|
||||
parser.AddParameter(ArgParseCpp::ParserParam("-e", "", ArgParseCpp::EqualParam, ArgParseCpp::Int));
|
||||
parser.PrintHelp();
|
||||
}
|
||||
if(0)
|
||||
{// sanitize the input arguments and display help whenever -h or --help is seen
|
||||
std::string argString = "programName -h blabla hehe hoho lalaland";
|
||||
Parser parser;
|
||||
parser.Parse(argString);
|
||||
}
|
||||
if(0)
|
||||
{// parse some boolean arguments
|
||||
std::string argString = "programName -v --all";
|
||||
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));
|
||||
parser.AddParameter(ArgParseCpp::ParserParam("-b", "--brief", ArgParseCpp::StandaloneParam));
|
||||
parser.AddParameter(ArgParseCpp::ParserParam("-z", "", ArgParseCpp::StandaloneParam));
|
||||
parser.PrintHelp();
|
||||
parser.Parse(argString);
|
||||
parser.PrintParsedArguments();
|
||||
}
|
||||
// if(0)
|
||||
{// parse single value arguments
|
||||
std::string argString = "programName -a 5 -b 12.654 -s blabla_mon_negro hehe";
|
||||
Parser parser;
|
||||
parser.AddParameter(ArgParseCpp::ParserParam("-a", "--all", ArgParseCpp::SingleValueParam, ArgParseCpp::Int));
|
||||
parser.AddParameter(ArgParseCpp::ParserParam("-b", "--brief", ArgParseCpp::SingleValueParam, ArgParseCpp::Double));
|
||||
parser.AddParameter(ArgParseCpp::ParserParam("-s", "", ArgParseCpp::SingleValueParam, ArgParseCpp::String));
|
||||
parser.PrintHelp();
|
||||
parser.Parse(argString);
|
||||
parser.PrintParsedArguments();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
src/utils.cpp
Normal file
1
src/utils.cpp
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include <utils.hpp>
|
||||
Loading…
Add table
Reference in a new issue