mirror of
https://github.com/cuberite/TCLAP.git
synced 2025-08-04 02:06:29 -04:00
Use ArgTraits instead of ValueExtractor specialization Bug 1711487
This commit is contained in:
parent
847b8c9478
commit
00f07eb977
@ -1,5 +1,6 @@
|
||||
|
||||
noinst_PROGRAMS = test1 test2 test3 test4 test5 test6 test7 test8 test9 test10
|
||||
noinst_PROGRAMS = test1 test2 test3 test4 test5 test6 test7 test8 test9 \
|
||||
test10 test11 test12
|
||||
|
||||
test1_SOURCES = test1.cpp
|
||||
test2_SOURCES = test2.cpp
|
||||
@ -11,6 +12,8 @@ test7_SOURCES = test7.cpp
|
||||
test8_SOURCES = test8.cpp
|
||||
test9_SOURCES = test9.cpp
|
||||
test10_SOURCES = test10.cpp
|
||||
test11_SOURCES = test11.cpp
|
||||
test12_SOURCES = test12.cpp
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include
|
||||
|
||||
|
52
examples/test11.cpp
Normal file
52
examples/test11.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "tclap/CmdLine.h"
|
||||
#include <iterator>
|
||||
|
||||
using namespace TCLAP;
|
||||
|
||||
// Define a simple 3D vector type
|
||||
struct Vect3D {
|
||||
double v[3];
|
||||
|
||||
// operator= will be used to assign to the vector
|
||||
Vect3D& operator=(const std::string &str)
|
||||
{
|
||||
std::istringstream iss(str);
|
||||
if (!(iss >> v[0] >> v[1] >> v[2]))
|
||||
throw TCLAP::ArgParseException(str + " is not a 3D vector");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::ostream& print(std::ostream &os) const
|
||||
{
|
||||
std::copy(v, v + 3, std::ostream_iterator<double>(os, " "));
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
// Create an ArgTraits for the 3D vector type that declares it to be
|
||||
// of string like type
|
||||
namespace TCLAP {
|
||||
template<>
|
||||
struct ArgTraits<Vect3D> {
|
||||
typedef StringLike ValueCategory;
|
||||
};
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
CmdLine cmd("Command description message", ' ', "0.9");
|
||||
ValueArg<Vect3D> vec("v", "vect", "vector",
|
||||
true, Vect3D(), "3D vector", cmd);
|
||||
|
||||
try {
|
||||
cmd.parse(argc, argv);
|
||||
} catch(std::exception &e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
vec.getValue().print(std::cout);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
68
examples/test12.cpp
Normal file
68
examples/test12.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include "tclap/CmdLine.h"
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace TCLAP;
|
||||
|
||||
// Define a simple 3D vector type
|
||||
struct Vect3D {
|
||||
double v[3];
|
||||
|
||||
// operator= will be used to assign to the vector
|
||||
Vect3D& operator=(const std::string &str)
|
||||
{
|
||||
std::istringstream iss(str);
|
||||
if (!(iss >> v[0] >> v[1] >> v[2]))
|
||||
throw TCLAP::ArgParseException(str + " is not a 3D vector");
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::ostream& print(std::ostream &os) const
|
||||
{
|
||||
std::copy(v, v + 3, std::ostream_iterator<double>(os, " "));
|
||||
return os;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream &os, const Vect3D &v)
|
||||
{
|
||||
return v.print(os);
|
||||
}
|
||||
|
||||
// Create an ArgTraits for the 3D vector type that declares it to be
|
||||
// of string like type
|
||||
namespace TCLAP {
|
||||
template<>
|
||||
struct ArgTraits<Vect3D> {
|
||||
typedef StringLike ValueCategory;
|
||||
};
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
CmdLine cmd("Command description message", ' ', "0.9");
|
||||
MultiArg<Vect3D> vec("v", "vect", "vector",
|
||||
true, "3D vector", cmd);
|
||||
|
||||
try {
|
||||
cmd.parse(argc, argv);
|
||||
} catch(std::exception &e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::copy(vec.begin(), vec.end(),
|
||||
std::ostream_iterator<Vect3D>(std::cout, "\n"));
|
||||
|
||||
std::cout << "REVERSED" << std::endl;
|
||||
|
||||
// use alt. form getValue()
|
||||
std::vector<Vect3D> v(vec.getValue());
|
||||
std::reverse(v.begin(), v.end());
|
||||
|
||||
std::copy(v.begin(), v.end(),
|
||||
std::ostream_iterator<Vect3D>(std::cout, "\n"));
|
||||
}
|
||||
|
@ -24,11 +24,27 @@
|
||||
#ifndef TCLAP_ARGUMENT_H
|
||||
#define TCLAP_ARGUMENT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#else
|
||||
#define HAVE_SSTREAM
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
|
||||
#if defined(HAVE_SSTREAM)
|
||||
#include <sstream>
|
||||
typedef std::istringstream istringstream;
|
||||
#elif defined(HAVE_STRSTREAM)
|
||||
#include <strstream>
|
||||
typedef std::istrstream istringstream;
|
||||
#else
|
||||
#error "Need a stringstream (sstream or strstream) to compile!"
|
||||
#endif
|
||||
|
||||
#include <tclap/ArgException.h>
|
||||
#include <tclap/Visitor.h>
|
||||
#include <tclap/CmdLineInterface.h>
|
||||
@ -350,6 +366,84 @@ typedef std::vector<Arg*>::iterator ArgVectorIterator;
|
||||
*/
|
||||
typedef std::list<Visitor*>::iterator VisitorListIterator;
|
||||
|
||||
// We use two empty structs to get compile type specialization
|
||||
// function to work
|
||||
|
||||
/**
|
||||
* A value like argument value type is a value that can be set using
|
||||
* operator>>. This is the default value type.
|
||||
*/
|
||||
struct ValueLike {};
|
||||
|
||||
/**
|
||||
* A string like argument value type is a value that can be set using
|
||||
* operator=(string). Usefull if the value type contains spaces which
|
||||
* will be broken up into individual tokens by operator>>.
|
||||
*/
|
||||
struct StringLike {};
|
||||
|
||||
/**
|
||||
* Arg traits are used to get compile type specialization when parsing
|
||||
* argument values. Using an ArgTraits you can specify the way that
|
||||
* values gets assigned to any particular type during parsing. The two
|
||||
* supported types are string like and value like.
|
||||
*/
|
||||
template<typename T>
|
||||
struct ArgTraits {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
/**
|
||||
* Strings have string like argument traits.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<std::string> {
|
||||
typedef StringLike ValueCategory;
|
||||
};
|
||||
|
||||
/*
|
||||
* Extract a value of type T from it's string representation contained
|
||||
* in strVal. The ValueLike parameter used to select the correct
|
||||
* specialization of ExtractValue depending on the value traits of T.
|
||||
* ValueLike traits use operator>> to assign the value from strVal.
|
||||
*/
|
||||
template<typename T> void
|
||||
ExtractValue(T &destVal, const std::string& strVal, ValueLike vl)
|
||||
{
|
||||
std::istringstream is(strVal);
|
||||
|
||||
int valuesRead = 0;
|
||||
while ( is.good() ) {
|
||||
if ( is.peek() != EOF )
|
||||
is >> destVal;
|
||||
else
|
||||
break;
|
||||
|
||||
valuesRead++;
|
||||
}
|
||||
|
||||
if ( is.fail() )
|
||||
throw( ArgParseException("Couldn't read argument value "
|
||||
"from string '" + strVal + "'"));
|
||||
|
||||
|
||||
if ( valuesRead > 1 )
|
||||
throw( ArgParseException("More than one valid value parsed from "
|
||||
"string '" + strVal + "'"));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract a value of type T from it's string representation contained
|
||||
* in strVal. The ValueLike parameter used to select the correct
|
||||
* specialization of ExtractValue depending on the value traits of T.
|
||||
* StringLike uses assignment (operator=) to assign from strVal.
|
||||
*/
|
||||
template<typename T> void
|
||||
ExtractValue(T &destVal, const std::string& strVal, StringLike sl)
|
||||
{
|
||||
destVal = strVal;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//BEGIN Arg.cpp
|
||||
|
@ -29,135 +29,7 @@
|
||||
#include <tclap/Arg.h>
|
||||
#include <tclap/Constraint.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#else
|
||||
#define HAVE_SSTREAM
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSTREAM)
|
||||
#include <sstream>
|
||||
#elif defined(HAVE_STRSTREAM)
|
||||
#include <strstream>
|
||||
#else
|
||||
#error "Need a stringstream (sstream or strstream) to compile!"
|
||||
#endif
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
template<class T> class MultiArg;
|
||||
|
||||
namespace MULTI_ARG_HELPER {
|
||||
|
||||
enum Error_e { EXTRACT_FAILURE = 1000, EXTRACT_TOO_MANY };
|
||||
|
||||
/**
|
||||
* This class is used to extract a value from an argument.
|
||||
* It is used because we need a special implementation to
|
||||
* deal with std::string and making a specialiced function
|
||||
* puts it in the T segment, thus generating link errors.
|
||||
* Having a specialiced class makes the symbols weak.
|
||||
* This is not pretty but I don't know how to make it
|
||||
* work any other way.
|
||||
*/
|
||||
template<class T>
|
||||
class ValueExtractor
|
||||
{
|
||||
friend class MultiArg<T>;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Reference to the vector of values where the result of the
|
||||
* extraction will be put.
|
||||
*/
|
||||
std::vector<T> &_values;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param values - Where the values extracted will be put.
|
||||
*/
|
||||
ValueExtractor(std::vector<T> &values) : _values(values) {}
|
||||
|
||||
/**
|
||||
* Method that will attempt to parse the input stream for values
|
||||
* of type T.
|
||||
* \param val - Where the values parsed will be put.
|
||||
*/
|
||||
int extractValue( const std::string& val )
|
||||
{
|
||||
T temp;
|
||||
|
||||
#if defined(HAVE_SSTREAM)
|
||||
std::istringstream is(val);
|
||||
#elif defined(HAVE_STRSTREAM)
|
||||
std::istrstream is(val.c_str());
|
||||
#else
|
||||
#error "Need a stringstream (sstream or strstream) to compile!"
|
||||
#endif
|
||||
|
||||
int valuesRead = 0;
|
||||
|
||||
while ( is.good() )
|
||||
{
|
||||
if ( is.peek() != EOF )
|
||||
is >> temp;
|
||||
else
|
||||
break;
|
||||
|
||||
valuesRead++;
|
||||
}
|
||||
|
||||
if ( is.fail() )
|
||||
return EXTRACT_FAILURE;
|
||||
|
||||
if ( valuesRead > 1 )
|
||||
return EXTRACT_TOO_MANY;
|
||||
|
||||
_values.push_back(temp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Specialization for string. This is necessary because istringstream
|
||||
* operator>> is not able to ignore spaces... meaning -x "X Y" will only
|
||||
* read 'X'... and thus the specialization.
|
||||
*/
|
||||
template<>
|
||||
class ValueExtractor<std::string>
|
||||
{
|
||||
friend class MultiArg<std::string>;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Reference to the vector of strings where the result of the
|
||||
* extraction will be put.
|
||||
*/
|
||||
std::vector<std::string> &_values;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param values - Where the strings extracted will be put.
|
||||
*/
|
||||
ValueExtractor(std::vector<std::string> &values) : _values(values) {}
|
||||
|
||||
/**
|
||||
* Method that will attempt to parse the input stream for values
|
||||
* of type std::string.
|
||||
* \param val - Where the values parsed will be put.
|
||||
*/
|
||||
int extractValue( const std::string& val )
|
||||
{
|
||||
_values.push_back( val );
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace MULTI_ARG_HELPER
|
||||
|
||||
/**
|
||||
* An argument that allows multiple values of type T to be specified. Very
|
||||
* similar to a ValueArg, except a vector of values will be returned
|
||||
@ -166,78 +38,83 @@ class ValueExtractor<std::string>
|
||||
template<class T>
|
||||
class MultiArg : public Arg
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
typedef std::vector<T> container_type;
|
||||
typedef typename container_type::iterator iterator;
|
||||
typedef typename container_type::const_iterator const_iterator;
|
||||
|
||||
/**
|
||||
* The list of values parsed from the CmdLine.
|
||||
*/
|
||||
std::vector<T> _values;
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The description of type T to be used in the usage.
|
||||
*/
|
||||
std::string _typeDesc;
|
||||
/**
|
||||
* The list of values parsed from the CmdLine.
|
||||
*/
|
||||
std::vector<T> _values;
|
||||
|
||||
/**
|
||||
* A list of constraint on this Arg.
|
||||
*/
|
||||
Constraint<T>* _constraint;
|
||||
/**
|
||||
* The description of type T to be used in the usage.
|
||||
*/
|
||||
std::string _typeDesc;
|
||||
|
||||
/**
|
||||
* Extracts the value from the string.
|
||||
* Attempts to parse string as type T, if this fails an exception
|
||||
* is thrown.
|
||||
* \param val - The string to be read.
|
||||
*/
|
||||
void _extractValue( const std::string& val );
|
||||
/**
|
||||
* A list of constraint on this Arg.
|
||||
*/
|
||||
Constraint<T>* _constraint;
|
||||
|
||||
bool _allowMore;
|
||||
/**
|
||||
* Extracts the value from the string.
|
||||
* Attempts to parse string as type T, if this fails an exception
|
||||
* is thrown.
|
||||
* \param val - The string to be read.
|
||||
*/
|
||||
void _extractValue( const std::string& val );
|
||||
|
||||
public:
|
||||
bool _allowMore;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
const std::string& typeDesc,
|
||||
Visitor* v = NULL);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
@ -245,45 +122,45 @@ class MultiArg : public Arg
|
||||
CmdLineInterface& parser,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
Constraint<T>* constraint,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
@ -291,41 +168,53 @@ class MultiArg : public Arg
|
||||
CmdLineInterface& parser,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Handles the processing of the argument.
|
||||
* This re-implements the Arg version of this method to set the
|
||||
* _value of the argument appropriately. It knows the difference
|
||||
* between labeled and unlabeled.
|
||||
* \param i - Pointer the the current argument in the list.
|
||||
* \param args - Mutable list of strings. Passed from main().
|
||||
*/
|
||||
virtual bool processArg(int* i, std::vector<std::string>& args);
|
||||
/**
|
||||
* Handles the processing of the argument.
|
||||
* This re-implements the Arg version of this method to set the
|
||||
* _value of the argument appropriately. It knows the difference
|
||||
* between labeled and unlabeled.
|
||||
* \param i - Pointer the the current argument in the list.
|
||||
* \param args - Mutable list of strings. Passed from main().
|
||||
*/
|
||||
virtual bool processArg(int* i, std::vector<std::string>& args);
|
||||
|
||||
/**
|
||||
* Returns a vector of type T containing the values parsed from
|
||||
* the command line.
|
||||
*/
|
||||
const std::vector<T>& getValue();
|
||||
/**
|
||||
* Returns a vector of type T containing the values parsed from
|
||||
* the command line.
|
||||
*/
|
||||
const std::vector<T>& getValue();
|
||||
|
||||
/**
|
||||
* Returns the a short id string. Used in the usage.
|
||||
* \param val - value to be used.
|
||||
*/
|
||||
virtual std::string shortID(const std::string& val="val") const;
|
||||
/**
|
||||
* Returns an iterator over the values parsed from the command
|
||||
* line.
|
||||
*/
|
||||
const_iterator begin() const { return _values.begin(); }
|
||||
|
||||
/**
|
||||
* Returns the a long id string. Used in the usage.
|
||||
* \param val - value to be used.
|
||||
*/
|
||||
virtual std::string longID(const std::string& val="val") const;
|
||||
/**
|
||||
* Returns the end of the values parsed from the command
|
||||
* line.
|
||||
*/
|
||||
const_iterator end() const { return _values.end(); }
|
||||
|
||||
/**
|
||||
* Once we've matched the first value, then the arg is no longer
|
||||
* required.
|
||||
*/
|
||||
virtual bool isRequired() const;
|
||||
/**
|
||||
* Returns the a short id string. Used in the usage.
|
||||
* \param val - value to be used.
|
||||
*/
|
||||
virtual std::string shortID(const std::string& val="val") const;
|
||||
|
||||
virtual bool allowMore();
|
||||
/**
|
||||
* Returns the a long id string. Used in the usage.
|
||||
* \param val - value to be used.
|
||||
*/
|
||||
virtual std::string longID(const std::string& val="val") const;
|
||||
|
||||
/**
|
||||
* Once we've matched the first value, then the arg is no longer
|
||||
* required.
|
||||
*/
|
||||
virtual bool isRequired() const;
|
||||
|
||||
virtual bool allowMore();
|
||||
|
||||
};
|
||||
|
||||
@ -492,24 +381,20 @@ bool MultiArg<T>::isRequired() const
|
||||
template<class T>
|
||||
void MultiArg<T>::_extractValue( const std::string& val )
|
||||
{
|
||||
MULTI_ARG_HELPER::ValueExtractor<T> ve(_values);
|
||||
|
||||
int err = ve.extractValue(val);
|
||||
try {
|
||||
T tmp;
|
||||
ExtractValue(tmp, val, typename ArgTraits<T>::ValueCategory());
|
||||
_values.push_back(tmp);
|
||||
} catch( ArgParseException &e) {
|
||||
throw ArgParseException(e.error(), toString());
|
||||
}
|
||||
|
||||
if ( err == MULTI_ARG_HELPER::EXTRACT_FAILURE )
|
||||
throw( ArgParseException("Couldn't read argument value "
|
||||
"from string '" + val + "'", toString() ) );
|
||||
|
||||
if(err == MULTI_ARG_HELPER::EXTRACT_TOO_MANY)
|
||||
throw( ArgParseException("More than one valid value "
|
||||
"parsed from string '" + val + "'",
|
||||
toString() ) );
|
||||
if ( _constraint != NULL )
|
||||
if ( ! _constraint->check( _values.back() ) )
|
||||
throw( CmdLineParseException( "Value '" + val +
|
||||
"' does not meet constraint: " +
|
||||
_constraint->description(),
|
||||
toString() ) );
|
||||
if ( _constraint != NULL )
|
||||
if ( ! _constraint->check( _values.back() ) )
|
||||
throw( CmdLineParseException( "Value '" + val +
|
||||
"' does not meet constraint: " +
|
||||
_constraint->description(),
|
||||
toString() ) );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
@ -29,135 +29,8 @@
|
||||
#include <tclap/Arg.h>
|
||||
#include <tclap/Constraint.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#else
|
||||
#define HAVE_SSTREAM
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSTREAM)
|
||||
#include <sstream>
|
||||
#elif defined(HAVE_STRSTREAM)
|
||||
#include <strstream>
|
||||
#else
|
||||
#error "Need a stringstream (sstream or strstream) to compile!"
|
||||
#endif
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
template<class T> class ValueArg;
|
||||
|
||||
namespace VALUE_ARG_HELPER {
|
||||
|
||||
enum Error_e { EXTRACT_FAILURE = 1000, EXTRACT_TOO_MANY };
|
||||
|
||||
/**
|
||||
* This class is used to extract a value from an argument.
|
||||
* It is used because we need a special implementation to
|
||||
* deal with std::string and making a specialiced function
|
||||
* puts it in the T segment, thus generating link errors.
|
||||
* Having a specialiced class makes the symbols weak.
|
||||
* This is not pretty but I don't know how to make it
|
||||
* work any other way.
|
||||
*/
|
||||
template<class T> class ValueExtractor
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
friend class ValueArg<T>;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Reference to the value where the result of the extraction will
|
||||
* be put.
|
||||
*/
|
||||
T &_value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param value - Where the value extracted will be put.
|
||||
*/
|
||||
ValueExtractor(T &value) : _value(value) { }
|
||||
|
||||
/**
|
||||
* Method that will attempt to parse the input stream for a value
|
||||
* of type T.
|
||||
* \param val - Where the value parsed will be put.
|
||||
*/
|
||||
int extractValue( const std::string& val )
|
||||
{
|
||||
|
||||
#if defined(HAVE_SSTREAM)
|
||||
std::istringstream is(val);
|
||||
#elif defined(HAVE_STRSTREAM)
|
||||
std::istrstream is(val.c_str());
|
||||
#else
|
||||
#error "Need a stringstream (sstream or strstream) to compile!"
|
||||
#endif
|
||||
|
||||
int valuesRead = 0;
|
||||
while ( is.good() )
|
||||
{
|
||||
if ( is.peek() != EOF )
|
||||
is >> _value;
|
||||
else
|
||||
break;
|
||||
|
||||
valuesRead++;
|
||||
}
|
||||
|
||||
if ( is.fail() )
|
||||
return EXTRACT_FAILURE;
|
||||
|
||||
if ( valuesRead > 1 )
|
||||
return EXTRACT_TOO_MANY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Specialization for string. This is necessary because istringstream
|
||||
* operator>> is not able to ignore spaces... meaning -x "X Y" will only
|
||||
* read 'X'... and thus the specialization.
|
||||
*/
|
||||
template<> class ValueExtractor<std::string>
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
friend class ValueArg<std::string>;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Reference to the value where the result of the extraction will
|
||||
* be put.
|
||||
*/
|
||||
std::string &_value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param value - Where the value extracted will be put.
|
||||
*/
|
||||
ValueExtractor(std::string &value) : _value(value) {}
|
||||
|
||||
/**
|
||||
* Method that will attempt to parse the input stream for a value
|
||||
* of type std::string.
|
||||
* \param val - Where the string parsed will be put.
|
||||
*/
|
||||
int extractValue( const std::string& val )
|
||||
{
|
||||
_value = val;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} //namespace VALUE_ARG_HELPER
|
||||
|
||||
/**
|
||||
* The basic labeled argument that parses a value.
|
||||
* This is a template class, which means the type T defines the type
|
||||
@ -500,25 +373,18 @@ std::string ValueArg<T>::longID(const std::string& val) const
|
||||
template<class T>
|
||||
void ValueArg<T>::_extractValue( const std::string& val )
|
||||
{
|
||||
VALUE_ARG_HELPER::ValueExtractor<T> ve(_value);
|
||||
|
||||
int err = ve.extractValue(val);
|
||||
|
||||
if ( err == VALUE_ARG_HELPER::EXTRACT_FAILURE )
|
||||
throw( ArgParseException("Couldn't read argument value from string '" +
|
||||
val + "'", toString() ) );
|
||||
|
||||
if ( err == VALUE_ARG_HELPER::EXTRACT_TOO_MANY )
|
||||
throw( ArgParseException(
|
||||
"More than one valid value parsed from string '" +
|
||||
val + "'", toString() ) );
|
||||
|
||||
if ( _constraint != NULL )
|
||||
if ( ! _constraint->check( _value ) )
|
||||
throw( CmdLineParseException( "Value '" + val +
|
||||
"' does not meet constraint: " +
|
||||
_constraint->description(),
|
||||
toString() ) );
|
||||
try {
|
||||
ExtractValue(_value, val, typename ArgTraits<T>::ValueCategory());
|
||||
} catch( ArgParseException &e) {
|
||||
throw ArgParseException(e.error(), toString());
|
||||
}
|
||||
|
||||
if ( _constraint != NULL )
|
||||
if ( ! _constraint->check( _value ) )
|
||||
throw( CmdLineParseException( "Value '" + val +
|
||||
+ "' does not meet constraint: "
|
||||
+ _constraint->description(),
|
||||
toString() ) );
|
||||
}
|
||||
|
||||
} // namespace TCLAP
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
let "suc = 0"
|
||||
let "fail = 0"
|
||||
NUMTEST=67
|
||||
|
||||
for (( tno = 1 ; $tno < 62 ; tno = $tno + 1 )); do
|
||||
for (( tno = 1 ; $tno <= $NUMTEST ; tno = $tno + 1 )); do
|
||||
./testCheck.sh $tno
|
||||
if [ "$?" -eq "0" ]; then
|
||||
echo "OK"
|
||||
|
9
tests/test63.out
Normal file
9
tests/test63.out
Normal file
@ -0,0 +1,9 @@
|
||||
PARSE ERROR:
|
||||
Required argument missing: vect
|
||||
|
||||
Brief USAGE:
|
||||
../examples/test11 -v <3D vector> [--] [--version] [-h]
|
||||
|
||||
For complete USAGE and HELP type:
|
||||
../examples/test11 --help
|
||||
|
13
tests/test63.sh
Normal file
13
tests/test63.sh
Normal file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
# this tests whether all required args are listed as
|
||||
# missing when no arguments are specified
|
||||
# failure
|
||||
../examples/test11 > tmp.out 2>&1
|
||||
|
||||
if cmp -s tmp.out $srcdir/test63.out; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
1
tests/test64.out
Normal file
1
tests/test64.out
Normal file
@ -0,0 +1 @@
|
||||
1 2 3
|
13
tests/test64.sh
Normal file
13
tests/test64.sh
Normal file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
# this tests whether all required args are listed as
|
||||
# missing when no arguments are specified
|
||||
# failure
|
||||
../examples/test11 -v "1 2 3" > tmp.out 2>&1
|
||||
|
||||
if cmp -s tmp.out $srcdir/test64.out; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
9
tests/test65.out
Normal file
9
tests/test65.out
Normal file
@ -0,0 +1,9 @@
|
||||
1 2 3
|
||||
4 5 6
|
||||
7 8 9
|
||||
-1 0.2 0.4
|
||||
REVERSED
|
||||
-1 0.2 0.4
|
||||
7 8 9
|
||||
4 5 6
|
||||
1 2 3
|
14
tests/test65.sh
Normal file
14
tests/test65.sh
Normal file
@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
# this tests whether all required args are listed as
|
||||
# missing when no arguments are specified
|
||||
# failure
|
||||
../examples/test12 -v "1 2 3" -v "4 5 6" -v "7 8 9" -v "-1 0.2 0.4" \
|
||||
> tmp.out 2>&1
|
||||
|
||||
if cmp -s tmp.out $srcdir/test65.out; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
9
tests/test66.out
Normal file
9
tests/test66.out
Normal file
@ -0,0 +1,9 @@
|
||||
PARSE ERROR:
|
||||
Required argument missing: vect
|
||||
|
||||
Brief USAGE:
|
||||
../examples/test12 -v <3D vector> ... [--] [--version] [-h]
|
||||
|
||||
For complete USAGE and HELP type:
|
||||
../examples/test12 --help
|
||||
|
13
tests/test66.sh
Normal file
13
tests/test66.sh
Normal file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
# this tests whether all required args are listed as
|
||||
# missing when no arguments are specified
|
||||
# failure
|
||||
../examples/test12 > tmp.out 2>&1
|
||||
|
||||
if cmp -s tmp.out $srcdir/test66.out; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
9
tests/test67.out
Normal file
9
tests/test67.out
Normal file
@ -0,0 +1,9 @@
|
||||
PARSE ERROR: Argument: -v (--vect)
|
||||
a 1 0.3 is not a 3D vector
|
||||
|
||||
Brief USAGE:
|
||||
../examples/test12 -v <3D vector> ... [--] [--version] [-h]
|
||||
|
||||
For complete USAGE and HELP type:
|
||||
../examples/test12 --help
|
||||
|
13
tests/test67.sh
Normal file
13
tests/test67.sh
Normal file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
# this tests whether all required args are listed as
|
||||
# missing when no arguments are specified
|
||||
# failure
|
||||
../examples/test12 -v "a 1 0.3" > tmp.out 2>&1
|
||||
|
||||
if cmp -s tmp.out $srcdir/test67.out; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
@ -7,7 +7,7 @@ if [ "$1" == "" ]
|
||||
then
|
||||
echo "USAGE: testCheck.sh <test num>"
|
||||
else
|
||||
cmd="./test$1.sh"
|
||||
cmd="sh ./test$1.sh"
|
||||
out="test$1.out"
|
||||
$cmd
|
||||
if cmp -s tmp.out $out
|
||||
|
Loading…
x
Reference in New Issue
Block a user