ArgParse can take required arguments

master
Denes Matetelki 13 years ago
parent 4efe0d3388
commit 45b40ae03b

@ -23,7 +23,7 @@ public:
BOOL BOOL
}; };
enum ValueRequired { enum Required {
OPTIONAL, OPTIONAL,
REQUIRED REQUIRED
}; };
@ -42,7 +42,10 @@ public:
* @param name short and/or long form: "-f,--foo" * @param name short and/or long form: "-f,--foo"
* The value can be retreived with this string passed to the argAs... functions. * The value can be retreived with this string passed to the argAs... functions.
* @param help Description of the argument, printed when --help is given. * @param help Description of the argument, printed when --help is given.
* @param type Type of the paramterer, required by the argument. * @param argRequired Argument is required or optional.
* It's a bad practice to have a required argument,
* "options", shall be optional.
* @param valueType Type of the paramterer, required by the argument.
* @param valueRequired Parameter requiered/optional after the argument. * @param valueRequired Parameter requiered/optional after the argument.
* @param valueName Default is the type. But some short text can be better. * @param valueName Default is the type. But some short text can be better.
* @param choices Comma separeted list of strings without whitespaces: * @param choices Comma separeted list of strings without whitespaces:
@ -51,8 +54,9 @@ public:
*/ */
void addArgument(const std::string name, void addArgument(const std::string name,
const std::string help, const std::string help,
const enum ValueType type = NONE, const ValueType valueType = NONE,
const enum ValueRequired valueRequired = REQUIRED, const Required argRequired = OPTIONAL,
const Required valueRequired = REQUIRED,
const std::string valueName = std::string(""), const std::string valueName = std::string(""),
const std::string choices = std::string("")); const std::string choices = std::string(""));
@ -71,8 +75,6 @@ public:
void parseArgs(const std::list<std::string> argList); void parseArgs(const std::list<std::string> argList);
// 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? // is this argument passed as a command line parameter?
bool foundArg(const std::string arg) const; bool foundArg(const std::string arg) const;
// argument is passed as a command line parameter, but has a value? // argument is passed as a command line parameter, but has a value?
@ -90,6 +92,12 @@ public:
private: private:
bool thereAreOptionalArgs() const;
bool thereAreRequiredArgs() const;
std::string printArgs(const Required argRequired) const;
void checkRequiredArgsFound() const;
void validateValue(const ArgParse::ValueType type, void validateValue(const ArgParse::ValueType type,
const std::string name, const std::string name,
const std::string choices, const std::string choices,
@ -112,8 +120,9 @@ private:
struct Argument { struct Argument {
const std::string m_help; const std::string m_help;
const enum ValueType m_type; const ValueType m_type;
const enum ValueRequired m_valueRequired; const Required m_argRequired;
const Required m_valueRequired;
const std::string m_valueName; const std::string m_valueName;
const std::string m_choices; const std::string m_choices;
std::string m_value; std::string m_value;
@ -121,8 +130,9 @@ private:
bool m_valueHasBeenSet; bool m_valueHasBeenSet;
Argument (const std::string help, Argument (const std::string help,
const enum ValueType type = NONE, const ValueType type = NONE,
const enum ValueRequired valueRequired = REQUIRED, const Required argRequired = OPTIONAL,
const Required valueRequired = REQUIRED,
const std::string valueName = std::string(""), const std::string valueName = std::string(""),
const std::string choices = std::string(""), const std::string choices = std::string(""),
const std::string value = std::string("")); const std::string value = std::string(""));

@ -20,13 +20,16 @@ void setUpArgs(ArgParse &argParse)
ArgParse::STRING ); ArgParse::STRING );
argParse.addArgument("-u, --user", argParse.addArgument("-u, --user",
"Username", "Username",
ArgParse::STRING ); ArgParse::STRING,
ArgParse::REQUIRED );
argParse.addArgument("-db, --database", argParse.addArgument("-db, --database",
"Database", "Database",
ArgParse::STRING ); ArgParse::STRING,
ArgParse::REQUIRED );
argParse.addArgument("-p, --password", argParse.addArgument("-p, --password",
"Password", "Password",
ArgParse::STRING ); ArgParse::STRING,
ArgParse::REQUIRED );
argParse.addArgument("-port", argParse.addArgument("-port",
"Port", "Port",
ArgParse::INT ); ArgParse::INT );
@ -39,7 +42,7 @@ void setUpArgs(ArgParse &argParse)
} }
bool getArgs( int argc, char* argv[], void getArgs( int argc, char* argv[],
ArgParse &argParse, ArgParse &argParse,
std::string &host, std::string &host,
std::string &user, std::string &user,
@ -49,12 +52,7 @@ bool getArgs( int argc, char* argv[],
int &port, int &port,
int &clientflags ) int &clientflags )
{ {
try {
argParse.parseArgs(argc, argv); argParse.parseArgs(argc, argv);
} catch (std::runtime_error e) {
std::cerr << e.what() << std::endl << std::endl;
return false;
}
argParse.argAsString("--host", host); argParse.argAsString("--host", host);
argParse.argAsString("-u, --user", user); argParse.argAsString("-u, --user", user);
@ -63,8 +61,6 @@ bool getArgs( int argc, char* argv[],
argParse.argAsInt("-port", port); argParse.argAsInt("-port", port);
argParse.argAsString("-s, --unix-socket", unixsocket); argParse.argAsString("-s, --unix-socket", unixsocket);
argParse.argAsInt("-f, --client-flags", clientflags); argParse.argAsInt("-f, --client-flags", clientflags);
return true;
} }
@ -94,12 +90,24 @@ int main(int argc, char* argv[] )
std::string host, user, db, pass, unixsocket; std::string host, user, db, pass, unixsocket;
int port, clientflags; int port, clientflags;
if ( !getArgs(argc, argv,
try {
getArgs( argc, argv,
argParse, argParse,
host, user, db, pass, unixsocket, host, user, db, pass, unixsocket,
port, clientflags ) || port, clientflags );
argParse.foundArg("-h, --help") ) } catch (std::runtime_error e) {
{ if ( argParse.foundArg("-h, --help") ) {
std::cout << argParse.usage() << std::endl;
return 1;
}
std::cerr << e.what() << std::endl
<< "Check usage: " << argv[0] << " --help" << std::endl;
return 1;
}
if ( argParse.foundArg("-h, --help") ) {
std::cout << argParse.usage() << std::endl; std::cout << argParse.usage() << std::endl;
return 1; return 1;
} }

@ -30,8 +30,9 @@ ArgParse::ArgParse(const std::string description,
void ArgParse::addArgument(const std::string arg, void ArgParse::addArgument(const std::string arg,
const std::string help, const std::string help,
const ValueType type, const ValueType valueType,
const ValueRequired valueRequired, const Required argRequired,
const Required valueRequired,
const std::string valueName, const std::string valueName,
const std::string choices) const std::string choices)
{ {
@ -44,7 +45,7 @@ void ArgParse::addArgument(const std::string arg,
append(" has been given before.")); append(" has been given before."));
int i; int i;
if ( type == INT && if ( valueType == INT &&
!choices.empty() && !choices.empty() &&
sscanf( choices.c_str(), "%d..%d", &i, &i ) != 2 ) sscanf( choices.c_str(), "%d..%d", &i, &i ) != 2 )
throw std::logic_error(std::string( arg ). throw std::logic_error(std::string( arg ).
@ -52,7 +53,7 @@ void ArgParse::addArgument(const std::string arg,
append("Range expected in a INT..INT format" )); append("Range expected in a INT..INT format" ));
float f; float f;
if ( type == FLOAT && if ( valueType == FLOAT &&
!choices.empty() && !choices.empty() &&
sscanf( choices.c_str(), "%f..%f", &f, &f ) != 2 ) sscanf( choices.c_str(), "%f..%f", &f, &f ) != 2 )
throw std::logic_error(std::string( arg ). throw std::logic_error(std::string( arg ).
@ -60,9 +61,10 @@ void ArgParse::addArgument(const std::string arg,
append("Range expected in a FLOAT..FLOAT format" )); append("Range expected in a FLOAT..FLOAT format" ));
Argument argument(help, Argument argument(help,
type, valueType,
argRequired,
valueRequired, valueRequired,
typeToString(type, valueName), typeToString(valueType, valueName),
choices, choices,
""); "");
m_params.insert(std::pair<std::string, Argument>(arg, argument)); m_params.insert(std::pair<std::string, Argument>(arg, argument));
@ -121,6 +123,182 @@ void ArgParse::parseArgs(const std::list<std::string> argList)
(*argMapIt).second.m_valueHasBeenSet = true; (*argMapIt).second.m_valueHasBeenSet = true;
++it; ++it;
} }
checkRequiredArgsFound();
}
bool ArgParse::foundArg(const std::string arg) const
{
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
{
ArgMap::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;
ArgMap::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;
ArgMap::const_iterator it = m_params.find(arg);
value = atoi((*it).second.m_value.c_str());
return true;
}
bool ArgParse::argAsFloat(const std::string arg, float &value) const
{
if ( !argHasValue(arg) )
return false;
ArgMap::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;
ArgMap::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;
bool oprionals = thereAreOptionalArgs();
bool required = thereAreRequiredArgs();
ss << "usage: " << m_programName
<< (required ? " <ARGS>" : "")
<< (oprionals ? " [OPTIONS]" : "")
<< std::endl;
if ( required ) {
ss << std::endl << "Required arguments:" << std::endl;
ss << printArgs(REQUIRED);
}
if ( oprionals ) {
ss << std::endl << "Options:" << std::endl;
ss << printArgs(OPTIONAL);
}
ss << std::endl;
ss << m_epilog;
return ss.str();;
}
bool ArgParse::thereAreOptionalArgs() const
{
for (ArgMap::const_iterator it = m_params.begin(); it != m_params.end(); ++it )
if ( (*it).second.m_argRequired == OPTIONAL )
return true;
return false;
}
bool ArgParse::thereAreRequiredArgs() const
{
for (ArgMap::const_iterator it = m_params.begin(); it != m_params.end(); ++it )
if ( (*it).second.m_argRequired == REQUIRED )
return true;
return false;
}
std::string
ArgParse::printArgs(const Required argRequired) const
{
int length;
std::string ret("");
ArgMap::const_iterator it;
for ( it = m_params.begin(); it != m_params.end(); it++ ) {
if ( (*it).second.m_argRequired != argRequired )
continue;
ret.append( (*it).first );
length = (*it).first.length();
if ( (*it).second.m_type != NONE ) {
ret.append( " " );
length++;
if ( (*it).second.m_valueRequired == OPTIONAL ) {
ret.append( "[" );
length ++;
}
if ( !(*it).second.m_choices.empty() ) {
ret.append( "{" ).append( (*it).second.m_choices).append( "}" );
length += (*it).second.m_choices.length() + 2;
} else {
ret.append( (*it).second.m_valueName );
length += (*it).second.m_valueName.length();
}
if ( (*it).second.m_valueRequired == OPTIONAL ) {
ret.append( "]" );
length++;
}
}
ret.append( std::string(30-length, ' ') );
ret.append( (*it).second.m_help );
ret.append("\n");
}
return ret;
}
void ArgParse::checkRequiredArgsFound() const
{
ArgMap::const_iterator it;
std::string missed;
for ( it = m_params.begin(); it != m_params.end(); ++it )
if ( (*it).second.m_argRequired && !(*it).second.m_found )
missed.append((*it).first).append("\n");
if ( !missed.empty() )
throw std::runtime_error(
std::string("Required argument(s) missing: \n").append(missed));
} }
@ -228,133 +406,16 @@ void ArgParse::validateBool( const std::string name,
} }
bool ArgParse::isArg(const std::string arg) const
{
ArgMap::const_iterator it = m_params.find(arg);
return it != m_params.end();
}
bool ArgParse::foundArg(const std::string arg) const
{
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
{
ArgMap::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;
ArgMap::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;
ArgMap::const_iterator it = m_params.find(arg);
value = atoi((*it).second.m_value.c_str());
return true;
}
bool ArgParse::argAsFloat(const std::string arg, float &value) const
{
if ( !argHasValue(arg) )
return false;
ArgMap::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;
ArgMap::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;
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 != 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();
}
if ( (*it).second.m_valueRequired == OPTIONAL ) {
ss << "]";
length++;
}
}
ss << std::string(30-length, ' ');
ss << (*it).second.m_help << std::endl;
}
}
ss << std::endl;
ss << m_epilog << std::endl;
return ss.str();;
}
ArgParse::Argument::Argument (const std::string help, ArgParse::Argument::Argument (const std::string help,
const enum ValueType type, const ValueType type,
const enum ValueRequired valueRequired, const Required argRequired,
const Required valueRequired,
const std::string valueName, const std::string valueName,
const std::string choices, const std::string choices,
const std::string value) const std::string value)
: m_help(help) : m_help(help)
, m_type(type) , m_type(type)
, m_argRequired(argRequired)
, m_valueRequired(valueRequired) , m_valueRequired(valueRequired)
, m_valueName(valueName) , m_valueName(valueName)
, m_choices(choices) , m_choices(choices)

@ -23,10 +23,10 @@ public:
TS_ASSERT_EQUALS( argParse.usage(), std::string( TS_ASSERT_EQUALS( argParse.usage(), std::string(
"intro\n\n" "intro\n\n"
"usage: [OPTION]\n\n" "usage: [OPTIONS]\n\n"
"Options:\n" "Options:\n"
"-h, --help Prints this help message\n\n" "-h, --help Prints this help message\n\n"
"outro\n") ); "outro") );
} }
void testfindKeyinArgMap ( void ) void testfindKeyinArgMap ( void )
@ -66,8 +66,8 @@ public:
argParse.parseArgs(argc, argv); argParse.parseArgs(argc, argv);
TS_ASSERT_EQUALS( argParse.isArg("-s, --unix-socket"), false ); TS_ASSERT_EQUALS( argParse.foundArg("-s, --unix-socket"), false );
TS_ASSERT_EQUALS( argParse.isArg("-u, --user"), true ); TS_ASSERT_EQUALS( argParse.foundArg("-u, --user"), true );
} }
}; };

Loading…
Cancel
Save