From 8a294bd0e750389d4384e3292bb11e723943b25c Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Sat, 15 Oct 2011 22:17:45 +0200 Subject: [PATCH 1/3] python argParse like ArgParse class added --- include/ArgParse.hpp | 105 +++++++++++++++++++ src/ArgParse.cpp | 243 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 348 insertions(+) create mode 100644 include/ArgParse.hpp create mode 100644 src/ArgParse.cpp diff --git a/include/ArgParse.hpp b/include/ArgParse.hpp new file mode 100644 index 0000000..65a0e92 --- /dev/null +++ b/include/ArgParse.hpp @@ -0,0 +1,105 @@ +#ifndef ARGPARSE_HPP +#define ARGPARSE_HPP + +#include +#include +#include +#include + +// Aims for the functionality of Python argparse +// http://docs.python.org/library/argparse.html#module-argparse +class ArgParse +{ + +public: + + enum ValueType { + TYPE_NONE, + TYPE_STRING, + TYPE_INT, + TYPE_DOUBLE, + TYPE_BOOL + }; + + enum ValueRequired { + OPTIONAL, + REQUIRED + }; + + ArgParse(const std::string description, + const std::string epilog = std::string(""), + const bool add_Help = true); + + void addArgument(const std::string name, // "-f,--foo" + const std::string help, + const enum ValueType type = TYPE_NONE, + const enum ValueRequired valueRequired = REQUIRED, + const std::string valueName = std::string(""), + const std::string choices = std::string("")); // "yes,no" or range: [1..100] + + + bool parseArgs(const int argc, + const char* argv[]) throw(std::runtime_error); + + bool parseArgs(const std::list argList) throw(std::runtime_error); + + // is this arg in the map of understood arguments? + bool isArg(const std::string arg) const; + // is this argument passed as a command line parameter? + bool foundArg(const std::string arg) const; + // argument is passed as a command line parameter, but has a value? + bool argHasValue(const std::string arg) const; + + // return true is arg exists and the arg in &value + // arg need to be the same string as in addArgument ( "-h,--help" ) + bool argAsString(const std::string arg, std::string &value) const; + bool argAsInt(const std::string arg, int &value) const; + bool argAsDouble(const std::string arg, double &value) const; + bool argAsBool(const std::string arg, bool &value) const; + + std::string usage() const; + + +private: + + struct Argument { + const std::string m_help; + const enum ValueType m_type; + const enum ValueRequired m_valueRequired; + const std::string m_valueName; + const std::string m_choices; + std::string m_value; + bool m_found; + bool m_valueHasBeenSet; + + Argument (const std::string help, + const enum ValueType type = TYPE_NONE, + const enum ValueRequired valueRequired = REQUIRED, + const std::string valueName = std::string(""), + const std::string choices = std::string(""), + const std::string value = std::string("")) + : m_help(help) + , m_type(type) + , m_valueRequired(valueRequired) + , m_valueName(valueName) + , m_choices(choices) + , m_value(value) + , m_found(false) + , m_valueHasBeenSet(false) {}; + }; + + // arg is just the shor or long form: "-h" or "--help" + std::map::iterator findElement(const std::string param); + + + std::string m_description; + std::string m_epilog; + std::string m_programName; + + std::map m_params; + + +}; // class ArgParse + + +#endif // ARGPARSE_HPP diff --git a/src/ArgParse.cpp b/src/ArgParse.cpp new file mode 100644 index 0000000..1eb5033 --- /dev/null +++ b/src/ArgParse.cpp @@ -0,0 +1,243 @@ +#include "../include/ArgParse.hpp" + + +#include +#include + +#include +#include +#include + + +ArgParse::ArgParse(const std::string description, + const std::string epilog, + const bool add_Help) + : m_description(description) + , m_epilog(epilog) + , m_programName() + , m_params() +{ + if (add_Help) + addArgument("-h,--help", "Prints this help message"); +} + + +void ArgParse::addArgument(const std::string arg, + const std::string help, + const ValueType type, + const ValueRequired valueRequired, + const std::string valueName, + const std::string choices) +{ + Argument argument(help, type, valueRequired, valueName, choices, ""); + m_params.insert(std::pair(arg, argument)); +} + + +bool ArgParse::parseArgs(const int argc, + const char* argv[]) throw(std::runtime_error) +{ + std::list argList; + for (int i = 0; i < argc; ++i ) + argList.push_back(argv[i]); + + return parseArgs(argList); +} + + +bool ArgParse::parseArgs(const std::list argList) throw(std::runtime_error) +{ + m_programName = argList.front(); + + // the wrok. + std::list::const_iterator it = argList.begin(); + for (++it; it != argList.end(); ++it ) { + + if ( (*it).at(0) != '-' ) + throw std::runtime_error(std::string(*it).append(" shall start with a dash.")); + + // inspect each arument + std::map::iterator it2 = findElement(*it); + if ( it2 == m_params.end() ) + throw std::runtime_error(std::string(*it).append(" is not known.")); + + if ( (*it2).second.m_found ) + throw std::runtime_error(std::string(*it).append(" has been given before.")); + + (*it2).second.m_found = true; + + if ( (*it2).second.m_type == TYPE_NONE ) + continue; + + std::list::const_iterator next = it; + next++; + + if ( next == argList.end() ) { + if ( (*it2).second.m_valueRequired == REQUIRED ) + throw std::runtime_error(std::string(*it).append(" requires a parameter.")); + + if ( (*it2).second.m_valueRequired == OPTIONAL ) + continue; + } + + if ( (*it2).second.m_valueRequired == OPTIONAL && findElement( *next ) != m_params.end() ) + continue; + + switch ( (*it2).second.m_type ) { + case TYPE_INT : { + int temp; + if ( sscanf( next->c_str(), "%d", &temp ) == 0 ) + throw std::runtime_error(std::string( *next ). + append(" is not an integer, required by ").append(*it)); + break; + } + case TYPE_DOUBLE : { + double temp; + if ( sscanf( next->c_str(), "%f", &temp ) == 0 ) + throw std::runtime_error(std::string( *next ). + append(" is not a double, required by ").append(*it)); + break; + } + case TYPE_BOOL : { + std::string temp = *next; + std::transform(temp.begin(), temp.end(),temp.begin(), ::toupper); + if ( temp != "TRUE" && temp != "FALSE" ) + throw std::runtime_error(std::string( *next ). + append(" is not a boolean, required by ").append(*it)); + break; + } + default: + break; + } + + (*it2).second.m_value = *next; + (*it2).second.m_valueHasBeenSet = true; + ++it; + } + return true; +} + + +bool ArgParse::isArg(const std::string arg) const +{ + std::map::const_iterator it = m_params.find(arg); + return it != m_params.end(); +} + + +bool ArgParse::foundArg(const std::string arg) const +{ + std::map::const_iterator it = m_params.find(arg); + return it != m_params.end() && (*it).second.m_found == true; +} + +bool ArgParse::argHasValue(const std::string arg) const +{ + std::map::const_iterator it = m_params.find(arg); + return it != m_params.end() && + (*it).second.m_found == true && + (*it).second.m_valueHasBeenSet; +} + + +bool ArgParse::argAsString(const std::string arg, std::string &value) const +{ + if ( !argHasValue(arg) ) + return false; + + std::map::const_iterator it = m_params.find(arg); + value = (*it).second.m_value; + return true; +} + + +bool ArgParse::argAsInt(const std::string arg, int &value) const +{ + if ( !argHasValue(arg) ) + return false; + + std::map::const_iterator it = m_params.find(arg); + value = atoi((*it).second.m_value.c_str()); + return true; +} + + +bool ArgParse::argAsDouble(const std::string arg, double &value) const +{ + if ( !argHasValue(arg) ) + return false; + + std::map::const_iterator it = m_params.find(arg); + value = atof((*it).second.m_value.c_str()); + return true; +} + + +bool ArgParse::argAsBool(const std::string arg, bool &value) const +{ + if ( !argHasValue(arg) ) + return false; + + std::map::const_iterator it = m_params.find(arg); + + std::string temp = (*it).second.m_value; + std::transform(temp.begin(), temp.end(),temp.begin(), ::toupper); + + value = temp == "TRUE"; + return true; +} + + +std::string ArgParse::usage() const +{ + std::stringstream ss; + + ss << m_description << std::endl << std::endl; + + ss << "usage: " << m_programName; + if (!m_params.empty()) { + ss << " [OPTION]" << std::endl << std::endl; + ss << "Options:" << std::endl; + int length; + std::map::const_iterator it; + for ( it = m_params.begin(); it != m_params.end(); it++ ) { + ss << (*it).first; + length = (*it).first.length(); + if ( (*it).second.m_type != TYPE_NONE ) { + if ((*it).second.m_valueRequired == REQUIRED ) { + ss << "=" << (*it).second.m_valueName; + length += (*it).second.m_valueName.length()+1; + } else { + ss << "[=" << (*it).second.m_valueName << "]"; + length += (*it).second.m_valueName.length() + 3; + } + } + ss << std::string(30-length, ' '); + ss << (*it).second.m_help << std::endl; + } + } + ss << std::endl; + ss << m_epilog << std::endl; + + return ss.str();; +} + +std::map::iterator +ArgParse::findElement(const std::string param) +{ + std::map::iterator it; + for( it = m_params.begin(); it != m_params.end(); ++it) { + + // if it's the short param at the beginning + if ( (*it).first.find(param) == 0 ) + return it; + + // or is it the long after the comma? + size_t commaPos = (*it).first.find(","); + if ( commaPos != std::string::npos && + (*it).first.find( param, commaPos+1 ) != std::string::npos ) + return it; + } + + return m_params.end(); +} \ No newline at end of file From dba6b1c91d2ff7d901d855fe2e0ddaf65424d1af Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Sun, 16 Oct 2011 16:41:41 +0200 Subject: [PATCH 2/3] ArgParse choices implemented --- include/ArgParse.hpp | 49 ++++---- src/ArgParse.cpp | 263 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 239 insertions(+), 73 deletions(-) diff --git a/include/ArgParse.hpp b/include/ArgParse.hpp index 65a0e92..e7dbc28 100644 --- a/include/ArgParse.hpp +++ b/include/ArgParse.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include // Aims for the functionality of Python argparse // http://docs.python.org/library/argparse.html#module-argparse @@ -14,11 +14,11 @@ class ArgParse public: enum ValueType { - TYPE_NONE, - TYPE_STRING, - TYPE_INT, - TYPE_DOUBLE, - TYPE_BOOL + NONE, + STRING, + INT, + DOUBLE, + BOOL }; enum ValueRequired { @@ -32,16 +32,15 @@ public: void addArgument(const std::string name, // "-f,--foo" const std::string help, - const enum ValueType type = TYPE_NONE, + const enum ValueType type = NONE, const enum ValueRequired valueRequired = REQUIRED, const std::string valueName = std::string(""), - const std::string choices = std::string("")); // "yes,no" or range: [1..100] - + const std::string choices = std::string("")); // {"yes,no"} or range: {1..100} + // throw(std::runtime_error) bool parseArgs(const int argc, - const char* argv[]) throw(std::runtime_error); - - bool parseArgs(const std::list argList) throw(std::runtime_error); + const char* argv[]); + bool parseArgs(const std::list argList); // is this arg in the map of understood arguments? bool isArg(const std::string arg) const; @@ -73,30 +72,32 @@ private: bool m_valueHasBeenSet; Argument (const std::string help, - const enum ValueType type = TYPE_NONE, + const enum ValueType type = NONE, const enum ValueRequired valueRequired = REQUIRED, const std::string valueName = std::string(""), const std::string choices = std::string(""), - const std::string value = std::string("")) - : m_help(help) - , m_type(type) - , m_valueRequired(valueRequired) - , m_valueName(valueName) - , m_choices(choices) - , m_value(value) - , m_found(false) - , m_valueHasBeenSet(false) {}; + const std::string value = std::string("")); + }; + + class argCompare { + public: + // short and long arg shall be compared with same amount of dashes + bool operator()(const std::string a,const std::string b) const; }; + typedef std::map ArgMap; + // arg is just the shor or long form: "-h" or "--help" - std::map::iterator findElement(const std::string param); + ArgMap::iterator findElement(const std::string param); + std::set parseCommaSepStringToSet(const std::string s) const; + std::string typeToString(const ValueType type, const std::string valueName) const; std::string m_description; std::string m_epilog; std::string m_programName; - std::map m_params; + ArgMap m_params; }; // class ArgParse diff --git a/src/ArgParse.cpp b/src/ArgParse.cpp index 1eb5033..e00d6aa 100644 --- a/src/ArgParse.cpp +++ b/src/ArgParse.cpp @@ -6,9 +6,14 @@ #include #include +#include + +#include + #include + ArgParse::ArgParse(const std::string description, const std::string epilog, const bool add_Help) @@ -29,13 +34,14 @@ void ArgParse::addArgument(const std::string arg, const std::string valueName, const std::string choices) { - Argument argument(help, type, valueRequired, valueName, choices, ""); + + Argument argument(help, type, valueRequired, typeToString(type, valueName), choices, ""); m_params.insert(std::pair(arg, argument)); } bool ArgParse::parseArgs(const int argc, - const char* argv[]) throw(std::runtime_error) + const char* argv[]) { std::list argList; for (int i = 0; i < argc; ++i ) @@ -45,7 +51,7 @@ bool ArgParse::parseArgs(const int argc, } -bool ArgParse::parseArgs(const std::list argList) throw(std::runtime_error) +bool ArgParse::parseArgs(const std::list argList) { m_programName = argList.front(); @@ -54,19 +60,21 @@ bool ArgParse::parseArgs(const std::list argList) throw(std::runtim for (++it; it != argList.end(); ++it ) { if ( (*it).at(0) != '-' ) - throw std::runtime_error(std::string(*it).append(" shall start with a dash.")); + throw std::runtime_error(std::string(*it). + append(" shall start with a dash.")); // inspect each arument - std::map::iterator it2 = findElement(*it); + ArgMap::iterator it2 = findElement(*it); if ( it2 == m_params.end() ) throw std::runtime_error(std::string(*it).append(" is not known.")); if ( (*it2).second.m_found ) - throw std::runtime_error(std::string(*it).append(" has been given before.")); + throw std::runtime_error(std::string(*it). + append(" has been given before.")); (*it2).second.m_found = true; - if ( (*it2).second.m_type == TYPE_NONE ) + if ( (*it2).second.m_type == NONE ) continue; std::list::const_iterator next = it; @@ -74,66 +82,125 @@ bool ArgParse::parseArgs(const std::list argList) throw(std::runtim if ( next == argList.end() ) { if ( (*it2).second.m_valueRequired == REQUIRED ) - throw std::runtime_error(std::string(*it).append(" requires a parameter.")); + throw std::runtime_error(std::string(*it). + append(" requires a parameter.")); if ( (*it2).second.m_valueRequired == OPTIONAL ) continue; } - if ( (*it2).second.m_valueRequired == OPTIONAL && findElement( *next ) != m_params.end() ) + if ( (*it2).second.m_valueRequired == OPTIONAL && + findElement( *next ) != m_params.end() ) continue; - switch ( (*it2).second.m_type ) { - case TYPE_INT : { - int temp; - if ( sscanf( next->c_str(), "%d", &temp ) == 0 ) - throw std::runtime_error(std::string( *next ). - append(" is not an integer, required by ").append(*it)); - break; - } - case TYPE_DOUBLE : { - double temp; - if ( sscanf( next->c_str(), "%f", &temp ) == 0 ) - throw std::runtime_error(std::string( *next ). - append(" is not a double, required by ").append(*it)); - break; - } - case TYPE_BOOL : { - std::string temp = *next; - std::transform(temp.begin(), temp.end(),temp.begin(), ::toupper); - if ( temp != "TRUE" && temp != "FALSE" ) - throw std::runtime_error(std::string( *next ). - append(" is not a boolean, required by ").append(*it)); - break; + switch ( (*it2).second.m_type ) { + case INT : { + int temp; + if ( sscanf( next->c_str(), "%d", &temp ) == 0 ) + throw std::runtime_error(std::string( *next ). + append(" is not an integer, required by ").append( *it )); + + if ( !(*it2).second.m_choices.empty() ) { + int lowerBound; + int upperBound; + if ( sscanf( (*it2).second.m_choices.c_str(), + "%d..%d", &lowerBound, &upperBound ) != 2 ) + throw std::logic_error(std::string( *it ). + append(" has syntax error. "). + append("Range expected in a INT..INT format" )); + + if ( temp < lowerBound || temp > upperBound ) + throw std::runtime_error(std::string( *it ). + append( " expects an integer in the range of {" ). + append( (*it2).second.m_choices). + append("}") ); + } + + break; + } + case DOUBLE : { + double temp; + if ( sscanf( next->c_str(), "%f", &temp ) == 0 ) + throw std::runtime_error(std::string( *next ). + append(" is not a double, required by ").append(*it)); + + if ( !(*it2).second.m_choices.empty() ) { + double lowerBound; + double upperBound; + if ( sscanf( (*it2).second.m_choices.c_str(), + "%f..%f", &lowerBound, &upperBound ) != 2 ) + throw std::logic_error(std::string( *it ). + append(" has syntax error. "). + append("Range expected in a DOUBLE..DOUBLE format" )); + + if ( temp < lowerBound || temp > upperBound ) + throw std::runtime_error(std::string( *it ). + append( " expects a double in the range of [" ). + append( (*it2).second.m_choices). + append("}") ); + } + + break; + } + case BOOL : { + std::string temp = *next; + std::transform(temp.begin(), temp.end(),temp.begin(), ::toupper); + if ( temp != "TRUE" && temp != "FALSE" ) + throw std::runtime_error(std::string( *next ). + append(" is not a boolean, required by ").append(*it)); + + if ( !(*it2).second.m_choices.empty() ) + throw std::logic_error(std::string( *next ). + append(" expects a boolean not choices.")); + + break; + } + case STRING : { + if ( !(*it2).second.m_choices.empty() ) { + + std::set choices = + parseCommaSepStringToSet( (*it2).second.m_choices ); + + if ( choices.find( *next ) == choices.end() ) + throw std::runtime_error(std::string( *next ). + append(" is not in the expected list of choices: {"). + append( (*it2).second.m_choices ). + append("}")); + } + + break; + } + + default: + break; } - default: - break; - } + (*it2).second.m_value = *next; (*it2).second.m_valueHasBeenSet = true; ++it; } + return true; } bool ArgParse::isArg(const std::string arg) const { - std::map::const_iterator it = m_params.find(arg); + ArgMap::const_iterator it = m_params.find(arg); return it != m_params.end(); } bool ArgParse::foundArg(const std::string arg) const { - std::map::const_iterator it = m_params.find(arg); + ArgMap::const_iterator it = m_params.find(arg); return it != m_params.end() && (*it).second.m_found == true; } bool ArgParse::argHasValue(const std::string arg) const { - std::map::const_iterator it = m_params.find(arg); + ArgMap::const_iterator it = m_params.find(arg); return it != m_params.end() && (*it).second.m_found == true && (*it).second.m_valueHasBeenSet; @@ -145,7 +212,7 @@ bool ArgParse::argAsString(const std::string arg, std::string &value) const if ( !argHasValue(arg) ) return false; - std::map::const_iterator it = m_params.find(arg); + ArgMap::const_iterator it = m_params.find(arg); value = (*it).second.m_value; return true; } @@ -156,7 +223,7 @@ bool ArgParse::argAsInt(const std::string arg, int &value) const if ( !argHasValue(arg) ) return false; - std::map::const_iterator it = m_params.find(arg); + ArgMap::const_iterator it = m_params.find(arg); value = atoi((*it).second.m_value.c_str()); return true; } @@ -167,7 +234,7 @@ bool ArgParse::argAsDouble(const std::string arg, double &value) const if ( !argHasValue(arg) ) return false; - std::map::const_iterator it = m_params.find(arg); + ArgMap::const_iterator it = m_params.find(arg); value = atof((*it).second.m_value.c_str()); return true; } @@ -178,7 +245,7 @@ bool ArgParse::argAsBool(const std::string arg, bool &value) const if ( !argHasValue(arg) ) return false; - std::map::const_iterator it = m_params.find(arg); + ArgMap::const_iterator it = m_params.find(arg); std::string temp = (*it).second.m_value; std::transform(temp.begin(), temp.end(),temp.begin(), ::toupper); @@ -199,17 +266,31 @@ std::string ArgParse::usage() const ss << " [OPTION]" << std::endl << std::endl; ss << "Options:" << std::endl; int length; - std::map::const_iterator it; + ArgMap::const_iterator it; for ( it = m_params.begin(); it != m_params.end(); it++ ) { ss << (*it).first; length = (*it).first.length(); - if ( (*it).second.m_type != TYPE_NONE ) { - if ((*it).second.m_valueRequired == REQUIRED ) { - ss << "=" << (*it).second.m_valueName; - length += (*it).second.m_valueName.length()+1; + if ( (*it).second.m_type != NONE ) { + + ss << " "; + length++; + + if ( (*it).second.m_valueRequired == OPTIONAL ) { + ss << "["; + length ++; + } + + if ( !(*it).second.m_choices.empty() ) { + ss << "{" << (*it).second.m_choices << "}"; + length += (*it).second.m_choices.length() + 2; } else { - ss << "[=" << (*it).second.m_valueName << "]"; - length += (*it).second.m_valueName.length() + 3; + ss << (*it).second.m_valueName; + length += (*it).second.m_valueName.length(); + } + + if ( (*it).second.m_valueRequired == OPTIONAL ) { + ss << "]"; + length++; } } ss << std::string(30-length, ' '); @@ -222,10 +303,43 @@ std::string ArgParse::usage() const return ss.str();; } + +ArgParse::Argument::Argument (const std::string help, + const enum ValueType type, + const enum ValueRequired valueRequired, + const std::string valueName, + const std::string choices, + const std::string value) + : m_help(help) + , m_type(type) + , m_valueRequired(valueRequired) + , m_valueName(valueName) + , m_choices(choices) + , m_value(value) + , m_found(false) + , m_valueHasBeenSet(false) +{ + +} + + +bool +ArgParse::argCompare::operator()(const std::string a,const std::string b) const +{ + if ( a.at(1) == '-' && b.at(1) != '-' ) + return a.substr(1) < b; + + if ( b.at(1) == '-' && a.at(1) != '-' ) + return a < b.substr(1); + + return a::iterator ArgParse::findElement(const std::string param) { - std::map::iterator it; + ArgMap::iterator it; for( it = m_params.begin(); it != m_params.end(); ++it) { // if it's the short param at the beginning @@ -240,4 +354,55 @@ ArgParse::findElement(const std::string param) } return m_params.end(); +} + +std::set +ArgParse::parseCommaSepStringToSet(const std::string s) const +{ + std::string tmp(s); + std::set stringSet; + + size_t pos; + std::string element; + + while ( !tmp.empty() ) { + pos = tmp.find(','); + if (pos == std::string::npos) { + element = tmp; + tmp = ""; + } else { + element = tmp.substr(0,pos); + tmp = tmp.substr(pos+1); + } + + // if ( element.empty() ) ... ? + + if ( stringSet.find(element) != stringSet.end() ) { + throw std::logic_error( std::string( element ). + append(" listed twice in ").append(s) ); + } + + stringSet.insert(element); + } + + return stringSet; +} + +std::string ArgParse::typeToString(const ValueType type, std::string valueName) const +{ + if ( type != NONE && valueName.empty() ) { + switch ( type ) { + case INT : + return "INT"; + case DOUBLE : + return "DOUBLE"; + break; + case BOOL : + return "BOOL"; + break; + default: + return ""; + } + } + return valueName; } \ No newline at end of file From d1bdd12a2c2d3183c46aa34b697dd863a966d843 Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Sun, 16 Oct 2011 17:43:12 +0200 Subject: [PATCH 3/3] ArgParse is doxygen-commented --- include/ArgParse.hpp | 51 +++++++++++++++++++++++++++++++++----------- src/ArgParse.cpp | 15 ++++++------- 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/include/ArgParse.hpp b/include/ArgParse.hpp index e7dbc28..482eb5e 100644 --- a/include/ArgParse.hpp +++ b/include/ArgParse.hpp @@ -6,8 +6,10 @@ #include #include -// Aims for the functionality of Python argparse -// http://docs.python.org/library/argparse.html#module-argparse +/** @brief Aim to achieve the functionality of Python argparse + * + * http://docs.python.org/library/argparse.html#module-argparse + */ class ArgParse { @@ -26,21 +28,46 @@ public: REQUIRED }; + /** @param description Exmplanation, before the usage lines. + * @param epilog Lines after the usage and options. Usually contact e-mail. + * @param addHelp Add a "-h,--help" option. + */ ArgParse(const std::string description, const std::string epilog = std::string(""), - const bool add_Help = true); - - void addArgument(const std::string name, // "-f,--foo" + const bool addHelp = true); + + /** @brief Adds an argument which the object will accept. + * + * @param name short and/or long form: "-f,--foo" + * @param help Description of the argument, printed when --help is given. + * @param type Type of the paramterer, required by the argument. + * @param valueRequired Parameter requiered/optional after the argument. + * @param valueName Default is the type. But some short text can be better. + * @param choices Comma separeted list of strings: "yes,no,maybe" + * or a range accepted numbers: NUM..NUM + */ + void addArgument(const std::string name, const std::string help, const enum ValueType type = NONE, const enum ValueRequired valueRequired = REQUIRED, const std::string valueName = std::string(""), - const std::string choices = std::string("")); // {"yes,no"} or range: {1..100} - - // throw(std::runtime_error) - bool parseArgs(const int argc, + const std::string choices = std::string("")); + + /** @brief Parse command line arguments according to the accepted arguments. + * + * Wrapper around the other version of parseArgs. + * + * @param argc Argumetn counter of the main function. + * @param argv Argument vector of the main function. + * @throw std::runtime_error When the command line args are bad. + * Shall be cought be the client code! + * @throw std::logic_error If the addArgument was bad. + * @todo addArgument shall handle this! + */ + void parseArgs(const int argc, const char* argv[]); - bool parseArgs(const std::list argList); + + void parseArgs(const std::list argList); // is this arg in the map of understood arguments? bool isArg(const std::string arg) const; @@ -80,8 +107,8 @@ private: }; class argCompare { - public: - // short and long arg shall be compared with same amount of dashes + public: + // short and long arg shall be compared with same amount of dashes bool operator()(const std::string a,const std::string b) const; }; diff --git a/src/ArgParse.cpp b/src/ArgParse.cpp index e00d6aa..72b42cd 100644 --- a/src/ArgParse.cpp +++ b/src/ArgParse.cpp @@ -16,13 +16,13 @@ ArgParse::ArgParse(const std::string description, const std::string epilog, - const bool add_Help) + const bool addHelp) : m_description(description) , m_epilog(epilog) , m_programName() , m_params() { - if (add_Help) + if (addHelp) addArgument("-h,--help", "Prints this help message"); } @@ -51,7 +51,7 @@ bool ArgParse::parseArgs(const int argc, } -bool ArgParse::parseArgs(const std::list argList) +void ArgParse::parseArgs(const std::list argList) { m_programName = argList.front(); @@ -180,15 +180,13 @@ bool ArgParse::parseArgs(const std::list argList) (*it2).second.m_valueHasBeenSet = true; ++it; } - - return true; } -bool ArgParse::isArg(const std::string arg) const +void ArgParse::isArg(const std::string arg) const { ArgMap::const_iterator it = m_params.find(arg); - return it != m_params.end(); + it != m_params.end(); } @@ -388,7 +386,8 @@ ArgParse::parseCommaSepStringToSet(const std::string s) const return stringSet; } -std::string ArgParse::typeToString(const ValueType type, std::string valueName) const +std::string +ArgParse::typeToString(const ValueType type, std::string valueName) const { if ( type != NONE && valueName.empty() ) { switch ( type ) {