2013-08-11 11:54:16 +02:00
|
|
|
/* (C) 2011 Viktor Lofgren
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Modifications:
|
|
|
|
*
|
|
|
|
* - Removed using namespace std from header
|
|
|
|
* - Changed Parameter container type from std::set to std::list to presume order
|
2013-08-13 22:43:36 +02:00
|
|
|
* - Changed arguments of Parameters to be a seperated arguments on the command line
|
|
|
|
* - Make the choice of receiving arguments or not in subclasses of CommonParameter
|
2013-08-11 11:54:16 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <list>
|
|
|
|
#include <vector>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <string>
|
|
|
|
#include <climits>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <sstream>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#ifndef GETOPTPP_H
|
|
|
|
#define GETOPTPP_H
|
|
|
|
|
|
|
|
namespace vlofgren {
|
|
|
|
|
|
|
|
class Parameter;
|
|
|
|
class ParserState;
|
|
|
|
|
|
|
|
class OptionsParser;
|
|
|
|
|
|
|
|
/** Container for a set of parameters */
|
|
|
|
|
|
|
|
class ParameterSet {
|
|
|
|
public:
|
|
|
|
|
|
|
|
/** Find a parameter by short option form */
|
|
|
|
Parameter& operator[](char c) const;
|
|
|
|
|
|
|
|
/** Find a parameter by long option form. */
|
2013-08-13 22:43:36 +02:00
|
|
|
Parameter& operator[](const std::string &s) const;
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
/** Factory method that adds a new parameter of
|
|
|
|
* type T to the set.
|
|
|
|
*
|
|
|
|
* This is just for convenience. It allows ParameterSet
|
|
|
|
* to manage the pointers, as well as (usually) making the
|
|
|
|
* code slightly easier to read.
|
|
|
|
*
|
|
|
|
* Do not try to add non-Parameter types lest you will invoke
|
|
|
|
* the wrath of gcc's template error messages.
|
|
|
|
*
|
|
|
|
* @returns The created parameter. The reference is valid
|
|
|
|
* as long as ParameterSet exists.
|
|
|
|
*/
|
|
|
|
template<typename T>
|
|
|
|
T &add(char shortName, const char* longName, const char* description);
|
|
|
|
|
|
|
|
ParameterSet() {}
|
|
|
|
~ParameterSet();
|
|
|
|
protected:
|
|
|
|
friend class OptionsParser;
|
2013-08-13 22:43:36 +02:00
|
|
|
std::list<Parameter*> parameters;
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
private:
|
|
|
|
ParameterSet(const ParameterSet& ps);
|
|
|
|
};
|
|
|
|
|
|
|
|
/** getopt()-style parser for command line arguments
|
|
|
|
*
|
|
|
|
* Matches each element in argv against given
|
|
|
|
* parameters, and collects non-parameter arguments
|
|
|
|
* (typically files) in a vector.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
class OptionsParser {
|
|
|
|
public:
|
|
|
|
OptionsParser(const char *programDesc);
|
|
|
|
virtual ~OptionsParser();
|
|
|
|
|
|
|
|
ParameterSet& getParameters();
|
|
|
|
|
|
|
|
/** Parse command line arguments */
|
2013-08-13 22:43:36 +02:00
|
|
|
void parse(int argc, const char* argv[]) throw(std::runtime_error);
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
/** Generate a usage screen */
|
|
|
|
void usage() const;
|
|
|
|
|
|
|
|
/** Return the name of the program, as
|
|
|
|
* given by argv[0]
|
|
|
|
*/
|
2013-08-13 22:43:36 +02:00
|
|
|
const std::string& programName() const;
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
/** Return a vector of each non-parameter */
|
2013-08-13 22:43:36 +02:00
|
|
|
const std::vector<std::string>& getFiles() const;
|
2013-08-11 11:54:16 +02:00
|
|
|
protected:
|
2013-08-13 22:43:36 +02:00
|
|
|
std::string argv0;
|
|
|
|
std::string fprogramDesc;
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
ParameterSet parameters;
|
2013-08-13 22:43:36 +02:00
|
|
|
std::vector<std::string> files;
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
friend class ParserState;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Corresponds to the state of the parsing, basically just a wrapper
|
|
|
|
* for a const_iterator that handles nicer.
|
|
|
|
*/
|
|
|
|
|
|
|
|
class ParserState {
|
|
|
|
public:
|
2013-08-13 22:43:36 +02:00
|
|
|
const std::string peek() const;
|
|
|
|
const std::string get() const;
|
2013-08-11 11:54:16 +02:00
|
|
|
void advance();
|
|
|
|
bool end() const;
|
|
|
|
protected:
|
2013-12-19 22:02:02 +01:00
|
|
|
ParserState(/*OptionsParser &opts,*/ std::vector<std::string>& args);
|
2013-08-11 11:54:16 +02:00
|
|
|
private:
|
|
|
|
friend class OptionsParser;
|
|
|
|
|
2013-12-19 22:02:02 +01:00
|
|
|
// OptionsParser &opts;
|
2013-08-13 22:43:36 +02:00
|
|
|
const std::vector<std::string> &arguments;
|
|
|
|
std::vector<std::string>::const_iterator iterator;
|
2013-08-11 11:54:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Abstract base class of all parameters
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
class Parameter {
|
|
|
|
public:
|
|
|
|
|
|
|
|
/** Generic exception thrown when a parameter is malformed
|
|
|
|
*/
|
2013-08-13 22:43:36 +02:00
|
|
|
class ParameterRejected : public std::runtime_error {
|
2013-08-11 11:54:16 +02:00
|
|
|
public:
|
2013-08-13 22:43:36 +02:00
|
|
|
ParameterRejected(const std::string& s) : std::runtime_error(s) {}
|
2013-08-11 11:54:16 +02:00
|
|
|
ParameterRejected() : runtime_error("") {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Exception thrown when a parameter did not expect an argument */
|
|
|
|
class UnexpectedArgument : public ParameterRejected {
|
|
|
|
public:
|
2013-08-13 22:43:36 +02:00
|
|
|
UnexpectedArgument(const std::string &s) : ParameterRejected(s) {}
|
2013-08-11 11:54:16 +02:00
|
|
|
UnexpectedArgument() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Exception thrown when a parameter expected an argument */
|
|
|
|
class ExpectedArgument : public ParameterRejected {
|
|
|
|
public:
|
2013-08-13 22:43:36 +02:00
|
|
|
ExpectedArgument(const std::string &s) : ParameterRejected(s) {}
|
2013-08-11 11:54:16 +02:00
|
|
|
ExpectedArgument() {}
|
|
|
|
};
|
|
|
|
|
2013-08-13 22:43:36 +02:00
|
|
|
Parameter(char shortOption, const std::string & longOption, const std::string & description);
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
virtual ~Parameter();
|
|
|
|
|
|
|
|
/** Test whether the parameter has been set */
|
|
|
|
virtual bool isSet() const = 0;
|
|
|
|
|
|
|
|
/** This parameter's line in OptionsParser::usage() */
|
2013-08-13 22:43:36 +02:00
|
|
|
virtual std::string usageLine() const = 0;
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
/** Description of the parameter (rightmost field in OptionsParser::usage()) */
|
2013-08-13 22:43:36 +02:00
|
|
|
const std::string& description() const;
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
/** The long name of this parameter (e.g. "--option"), without the dash. */
|
2013-08-13 22:43:36 +02:00
|
|
|
const std::string& longOption() const;
|
2013-08-11 11:54:16 +02:00
|
|
|
|
2013-08-13 22:43:36 +02:00
|
|
|
/** Check if this parameters has a short option */
|
|
|
|
bool hasShortOption() const;
|
2013-08-11 13:13:19 +02:00
|
|
|
|
2013-08-11 11:54:16 +02:00
|
|
|
/** The short name of this parameter (e.g. "-o"), without the dash. */
|
|
|
|
char shortOption() const;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
/** Receive a potential parameter from the parser (and determien if it's ours)
|
|
|
|
*
|
|
|
|
* The parser will pass each potential parameter through it's registered parameters'
|
|
|
|
* receive function.
|
|
|
|
*
|
|
|
|
* @throw ParameterRejected if the parameter belongs to us, but is malformed somehow.
|
|
|
|
*
|
|
|
|
* @param state Allows access to the current argument. This is a fairly powerful
|
|
|
|
* iterator that technically allows for more complex grammar than what is
|
|
|
|
* presently used.
|
|
|
|
*/
|
2013-08-13 22:43:36 +02:00
|
|
|
virtual int receive(ParserState& state) throw(ParameterRejected) = 0;
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
friend class OptionsParser;
|
|
|
|
|
|
|
|
char fshortOption;
|
2013-08-13 22:43:36 +02:00
|
|
|
const std::string flongOption;
|
|
|
|
const std::string fdescription;
|
2013-08-11 11:54:16 +02:00
|
|
|
private:
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Abstract base class of all parameters
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
class Switchable;
|
|
|
|
|
|
|
|
/** Base class for most parameter implementations.
|
|
|
|
*
|
|
|
|
* It parses the argument in receive() and if it matches,
|
|
|
|
* calls receiveSwitch() or receiveArgument() which are implemented
|
|
|
|
* in child classes.
|
|
|
|
*
|
|
|
|
* The SwitchingBehavior mixin determines what happens if the argument
|
|
|
|
* is set multiple times.
|
|
|
|
*/
|
|
|
|
|
|
|
|
template<typename SwitchingBehavior=Switchable>
|
|
|
|
class CommonParameter : public Parameter, protected SwitchingBehavior {
|
|
|
|
public:
|
|
|
|
|
|
|
|
/** Test whether the parameter has been set */
|
|
|
|
virtual bool isSet() const;
|
|
|
|
|
|
|
|
CommonParameter(char shortOption, const char *longOption,
|
|
|
|
const char* description);
|
|
|
|
virtual ~CommonParameter();
|
|
|
|
|
2013-08-13 22:43:36 +02:00
|
|
|
virtual std::string usageLine() const;
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
protected:
|
|
|
|
/** Parse the argument given by state, and dispatch either
|
|
|
|
* receiveSwitch() or receiveArgument() accordingly.
|
|
|
|
*
|
|
|
|
* @param state The current argument being parsed.
|
2013-08-13 22:43:36 +02:00
|
|
|
* @return The number of parameters taken from the input
|
2013-08-11 11:54:16 +02:00
|
|
|
*/
|
2013-08-13 22:43:36 +02:00
|
|
|
virtual int receive(ParserState& state) throw(ParameterRejected) = 0;
|
2013-08-11 11:54:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/** This class (used as a mixin) defines how a parameter
|
|
|
|
* behaves when switched on, specifically when switched on multiple times.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
class Switchable {
|
|
|
|
public:
|
|
|
|
class SwitchingError : public Parameter::ParameterRejected {};
|
|
|
|
|
|
|
|
/** Test whether the parameter has been set */
|
|
|
|
virtual bool isSet() const;
|
|
|
|
|
|
|
|
/** Set the parameter
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
virtual void set() throw (SwitchingError) = 0;
|
|
|
|
|
|
|
|
virtual ~Switchable();
|
|
|
|
Switchable();
|
|
|
|
protected:
|
|
|
|
bool fset;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Switching behavior that does not complain when set multiple times. */
|
|
|
|
class MultiSwitchable : public Switchable {
|
|
|
|
public:
|
|
|
|
virtual ~MultiSwitchable();
|
|
|
|
virtual void set() throw(SwitchingError);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Switching behavior that allows switching only once.
|
|
|
|
*
|
|
|
|
* This is typically what you want if your parameter has an argument.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
class UniquelySwitchable : public Switchable {
|
|
|
|
public:
|
|
|
|
|
|
|
|
virtual ~UniquelySwitchable();
|
|
|
|
|
|
|
|
/** Set the parameter
|
|
|
|
*
|
|
|
|
* @throw SwitchingError Thrown if the parameter is already set.
|
|
|
|
*/
|
|
|
|
virtual void set() throw (SwitchingError);
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Switching behavior that makes possible allows presettable parameters,
|
|
|
|
* that is, it can either be set by the program, or by a command line argument,
|
|
|
|
* and the command-line part is UniquelySwitchable, but the program part
|
|
|
|
* is MultiSwitchable (and is set by preset())
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
class PresettableUniquelySwitchable : public UniquelySwitchable {
|
|
|
|
public:
|
|
|
|
|
|
|
|
/** Test whether the parameter has been set OR preset */
|
|
|
|
virtual bool isSet() const;
|
|
|
|
|
|
|
|
/** Call if the parameter has been set.
|
|
|
|
*
|
|
|
|
* @throw SwitchingError thrown if the parameter is already set
|
|
|
|
* (doesn't care if it's been pre-set)
|
|
|
|
*/
|
|
|
|
virtual void set() throw (Switchable::SwitchingError);
|
|
|
|
|
|
|
|
/** Call if the parameter has been preset */
|
|
|
|
virtual void preset();
|
|
|
|
|
|
|
|
virtual ~PresettableUniquelySwitchable();
|
|
|
|
private:
|
|
|
|
MultiSwitchable fpreset;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Parameter that does not take an argument, and throws an exception
|
|
|
|
* if an argument is given */
|
|
|
|
|
2013-08-11 21:49:11 +02:00
|
|
|
template<typename SwitchingBehavior=MultiSwitchable>
|
|
|
|
class SwitchParameter : public CommonParameter<SwitchingBehavior> {
|
2013-08-11 11:54:16 +02:00
|
|
|
public:
|
|
|
|
SwitchParameter(char shortOption, const char *longOption,
|
|
|
|
const char* description);
|
|
|
|
virtual ~SwitchParameter();
|
|
|
|
|
|
|
|
protected:
|
2013-08-13 22:43:36 +02:00
|
|
|
virtual int receive(ParserState& state) throw(Parameter::ParameterRejected);
|
2013-08-11 11:54:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/** Plain-Old-Data parameter. Performs input validation.
|
|
|
|
*
|
|
|
|
* Currently only supports int, long and double, but extending
|
|
|
|
* it to other types (even non-POD) is as easy as partial template specialization.
|
|
|
|
*
|
|
|
|
* Specifically, you need to specialize validate().
|
|
|
|
*/
|
|
|
|
|
2013-08-11 21:49:11 +02:00
|
|
|
template<typename T, typename SwitchingBehavior=PresettableUniquelySwitchable>
|
|
|
|
class PODParameter : public CommonParameter<SwitchingBehavior> {
|
2013-08-11 11:54:16 +02:00
|
|
|
public:
|
|
|
|
PODParameter(char shortOption, const char *longOption,
|
|
|
|
const char* description);
|
|
|
|
virtual ~PODParameter();
|
|
|
|
|
|
|
|
/* Retreive the value of the argument. Throws an exception if
|
|
|
|
* the value hasn't been set (test with isSet())
|
|
|
|
*/
|
|
|
|
T getValue() const;
|
|
|
|
|
|
|
|
/** Type-casting operator, for convenience. */
|
|
|
|
operator T() const;
|
|
|
|
|
|
|
|
/** Set a default value for this parameter */
|
|
|
|
virtual void setDefault(T value);
|
|
|
|
|
|
|
|
std::string usageLine() const;
|
|
|
|
protected:
|
2013-08-13 22:43:36 +02:00
|
|
|
virtual int receive(ParserState& state) throw(Parameter::ParameterRejected);
|
2013-08-11 21:49:11 +02:00
|
|
|
|
2013-08-11 11:54:16 +02:00
|
|
|
/** Validation function for the data type.
|
|
|
|
*
|
|
|
|
* @throw ParameterRejected if the argument does not conform to this data type.
|
|
|
|
* @return the value corresponding to the argument.
|
|
|
|
*/
|
2013-08-13 22:43:36 +02:00
|
|
|
virtual T validate(const std::string& s) throw (Parameter::ParameterRejected);
|
2013-08-11 11:54:16 +02:00
|
|
|
|
|
|
|
T value;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
typedef PODParameter<int> IntParameter;
|
|
|
|
typedef PODParameter<long> LongParameter;
|
|
|
|
typedef PODParameter<double> DoubleParameter;
|
|
|
|
typedef PODParameter<std::string> StringParameter;
|
|
|
|
|
|
|
|
#include "parameter.include.cc"
|
|
|
|
|
|
|
|
} //namespace
|
|
|
|
|
|
|
|
#endif
|