refactor at value validating

master
Denes Matetelki 13 years ago
parent 7226f1494c
commit fd232c3114

@ -45,8 +45,9 @@ public:
* @param type Type of the paramterer, required by the argument. * @param type 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: "yes,no,maybe" * @param choices Comma separeted list of strings without whitespaces:
* or a range accepted numbers: NUM..NUM * "yes,no,maybe"
* or a range accepted numbers: "INT..INT", "DOUBLE..DOUBLE"
*/ */
void addArgument(const std::string name, void addArgument(const std::string name,
const std::string help, const std::string help,
@ -89,6 +90,26 @@ public:
private: private:
void validateValue(const ArgParse::ValueType type,
const std::string name,
const std::string choices,
const std::string value) const;
void validateString( const std::string name,
const std::string choices,
const std::string value) const;
void validateInt( const std::string name,
const std::string choices,
const std::string value) const;
void validateFloat( const std::string name,
const std::string choices,
const std::string value) const;
void validateBool( const std::string name,
const std::string choices,
const std::string value) const;
struct Argument { struct Argument {
const std::string m_help; const std::string m_help;
const enum ValueType m_type; const enum ValueType m_type;
@ -120,7 +141,11 @@ private:
// arg is just the shor or long form: "-h" or "--help" // arg is just the shor or long form: "-h" or "--help"
ArgMap::iterator findKeyinArgMap(const std::string param); ArgMap::iterator findKeyinArgMap(const std::string param);
std::set<std::string> choicesStringToSet(const std::string s) const; std::set<std::string> choicesStringToSet(const std::string s) const;
std::string typeToString(const ValueType type, const std::string valueName) const;
/** @return with valueName if specified,
or the string version of the type enum otherwise */
std::string typeToString(const ValueType type,
const std::string valueName) const;
std::string m_description; std::string m_description;

@ -10,7 +10,7 @@
#include <stdexcept> #include <stdexcept>
#include <stdio.h> // sscan #include <cstdio> // sscan
#include <cctype> #include <cctype>
@ -42,6 +42,21 @@ void ArgParse::addArgument(const std::string arg,
throw std::logic_error(std::string(arg). throw std::logic_error(std::string(arg).
append(" has been given before.")); append(" has been given before."));
int i;
if ( type == INT &&
!choices.empty() &&
sscanf( choices.c_str(), "%d..%d", &i, &i ) != 2 )
throw std::logic_error(std::string( arg ).
append(" has syntax error. ").
append("Range expected in a INT..INT format" ));
float f;
if ( type == FLOAT &&
!choices.empty() &&
sscanf( choices.c_str(), "%f..%f", &f, &f ) != 2 )
throw std::logic_error(std::string( arg ).
append(" has syntax error. ").
append("Range expected in a FLOAT..FLOAT format" ));
Argument argument(help, Argument argument(help,
type, type,
@ -71,123 +86,147 @@ void ArgParse::parseArgs(const std::list<std::string> argList)
std::list<std::string>::const_iterator it = argList.begin(); std::list<std::string>::const_iterator it = argList.begin();
for (++it; it != argList.end(); ++it ) { for (++it; it != argList.end(); ++it ) {
// inspect each arument ArgMap::iterator argMapIt = findKeyinArgMap(*it);
ArgMap::iterator it2 = findKeyinArgMap(*it); if ( argMapIt == m_params.end() )
if ( it2 == m_params.end() )
throw std::runtime_error(std::string(*it).append(" is not known.")); throw std::runtime_error(std::string(*it).append(" is not known."));
(*argMapIt).second.m_found = true;
(*it2).second.m_found = true; if ( (*argMapIt).second.m_type == NONE )
if ( (*it2).second.m_type == NONE )
continue; continue;
std::list<std::string>::const_iterator next = it; std::list<std::string>::const_iterator next = it;
next++; next++;
if ( next == argList.end() ) { if ( next == argList.end() ) {
if ( (*it2).second.m_valueRequired == REQUIRED ) if ( (*argMapIt).second.m_valueRequired == REQUIRED )
throw std::runtime_error(std::string(*it). throw std::runtime_error(std::string(*it).
append(" requires a parameter.")); append(" requires a parameter."));
if ( (*it2).second.m_valueRequired == OPTIONAL ) if ( (*argMapIt).second.m_valueRequired == OPTIONAL )
continue; continue;
} }
if ( (*it2).second.m_valueRequired == OPTIONAL && if ( (*argMapIt).second.m_valueRequired == OPTIONAL &&
findKeyinArgMap( *next ) != m_params.end() ) findKeyinArgMap( *next ) != m_params.end() )
continue; continue;
switch ( (*it2).second.m_type ) { validateValue( (*argMapIt).second.m_type,
case INT : { (*argMapIt).first,
int temp; (*argMapIt).second.m_choices,
if ( sscanf( next->c_str(), "%d", &temp ) == 0 ) *next );
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 FLOAT : {
float temp;
if ( sscanf( next->c_str(), "%f", &temp ) == 0 )
throw std::runtime_error(std::string( *next ).
append(" is not a float, required by ").append(*it));
if ( !(*it2).second.m_choices.empty() ) {
float lowerBound;
float 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 float 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<std::string> choices = (*argMapIt).second.m_value = *next;
choicesStringToSet( (*it2).second.m_choices ); (*argMapIt).second.m_valueHasBeenSet = true;
++it;
}
}
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; void ArgParse::validateValue(const ArgParse::ValueType type,
} const std::string name,
const std::string choices,
const std::string value) const
{
switch ( type ) {
case INT :
validateInt(name, choices, value);
break;
case FLOAT :
validateFloat(name, choices, value);
break;
case BOOL :
validateBool(name, choices, value);
break;
case STRING :
validateString(name, choices, value);
break;
default:
break;
}
}
default:
break;
}
void ArgParse::validateString( const std::string name,
const std::string choices,
const std::string value) const
{
if ( !choices.empty() ) {
(*it2).second.m_value = *next; std::set<std::string> choicesSet = choicesStringToSet( choices );
(*it2).second.m_valueHasBeenSet = true;
++it; if ( choicesSet.find( value ) == choicesSet.end() )
throw std::runtime_error(std::string( value ).
append(" is not in the expected list of choices: {").
append( choices ).
append("}, required by ").
append( name ));
} }
} }
void ArgParse::validateInt( const std::string name,
const std::string choices,
const std::string value) const
{
int temp;
if ( sscanf( value.c_str(), "%d", &temp ) == 0 )
throw std::runtime_error(std::string( value ).
append(" is not an integer, required by ").append( name ));
if ( !choices.empty() ) {
int lowerBound;
int upperBound;
sscanf( choices.c_str(), "%d..%d", &lowerBound, &upperBound );
if ( temp < lowerBound || temp > upperBound )
throw std::runtime_error(std::string( name ).
append( " expects an integer in the range of {" ).
append( choices).
append("}") );
}
}
void ArgParse::validateFloat( const std::string name,
const std::string choices,
const std::string value) const
{
float temp;
if ( sscanf( value.c_str(), "%f", &temp ) == 0 )
throw std::runtime_error(std::string( value ).
append(" is not a float, required by ").append( name ));
if ( !choices.empty() ) {
float lowerBound;
float upperBound;
sscanf( choices.c_str(), "%f..%f", &lowerBound, &upperBound );
if ( temp < lowerBound || temp > upperBound )
throw std::runtime_error(std::string( name ).
append( " expects a float in the range of [" ).
append( choices).
append("}") );
}
}
void ArgParse::validateBool( const std::string name,
const std::string choices,
const std::string value) const
{
std::string temp = value;
std::transform(temp.begin(), temp.end(),temp.begin(), ::toupper);
if ( temp != "TRUE" && temp != "FALSE" )
throw std::runtime_error(std::string( value ).
append(" is not a boolean, required by ").append( name ));
if ( !choices.empty() )
throw std::logic_error(std::string( value ).
append(" expects a boolean not choices."));
}
bool ArgParse::isArg(const std::string arg) const bool ArgParse::isArg(const std::string arg) const
{ {
ArgMap::const_iterator it = m_params.find(arg); ArgMap::const_iterator it = m_params.find(arg);
@ -391,22 +430,25 @@ ArgParse::choicesStringToSet(const std::string s) const
return stringSet; return stringSet;
} }
std::string std::string
ArgParse::typeToString(const ValueType type, std::string valueName) const ArgParse::typeToString(const ValueType type, std::string valueName) const
{ {
if ( type != NONE && valueName.empty() ) { if ( !valueName.empty() )
switch ( type ) { return valueName;
case INT :
return "INT"; switch ( type ) {
case FLOAT : case NONE :
return "DOUBLE"; return "NONE";
break; case STRING :
case BOOL : return "STRING";
return "BOOL"; case INT :
break; return "INT";
default: case FLOAT :
return ""; return "DOUBLE";
} case BOOL :
return "BOOL";
default:
return "";
} }
return valueName;
} }
Loading…
Cancel
Save