-
David Flitney authoredDavid Flitney authored
options.h 10.31 KiB
// $Id$
#if !defined(OPTIONS_H)
#define OPTIONS_H
#include <stdexcept>
#include <string>
#include <map>
#define POSIX_SOURCE 1
namespace Utilities {
bool string_to_T(bool &b, const string& s);
bool string_to_T(string& d, const string& s);
bool string_to_T(int& i, const string& s);
bool string_to_T(float& v, const string& s);
typedef enum {
no_argument = 0, requires_argument, optional_argument
} ArgFlag;
/**
Provides behaviour common to all option types. Actual options are
declared using the templated Option class. The
OptionParser class can be used to parse command lines.
@see Option
@see OptionParser
@author Dave Flitney
@version 1.0b, Nov., 2000.
@package Options
*/
class BaseOption {
public:
/**
@param k comma seperated list of key aliases
@param ht the help text to be printed for this option
@param c if true then this option is compulsory
@param f one of no_argument, requires_argument, optional_argument
to indicate what arguments should be supplied
*/
BaseOption(const string& k, const string& ht, bool c, ArgFlag f):
key_(k), help_text_(ht), arg_flag_(f),
unset_(true), compulsory_(c) {}
/**
@return true if the option is compulsory
*/
bool compulsory() { return compulsory_; }
/**
@return true if the option requires an argument
*/
bool required() { return arg_flag_ == requires_argument; }
/**
@return true if the option has an optional argument
*/
bool optional() { return arg_flag_ == optional_argument; }
/**
@return true if the option has an argument at all
*/
bool has_arg() { return arg_flag_ != no_argument; }
/**
@return true if the option has been set
*/
bool set() { return !unset_; }
/**
@return true if the option remains unset
*/
bool unset() { return unset_; }
/*
@param arg A command line argument to be compared against
the list of possible keys for this option.
@return True if a match is found.
*/
bool matches(const string& arg);
/*
@return This options key string.
*/
const string& key() const { return key_; }
/*
@return This options help text.
*/
const string& help_text() const { return help_text_; }
/*
@param Sets the value for this option. Is overridden in the type
specific template class Option.
*/
virtual bool set_value(const string& vs) = 0;
virtual ~BaseOption() {}
private:
string key_, help_text_;
ArgFlag arg_flag_;
protected:
bool unset_, compulsory_;
};
ostream& operator<<(ostream &os, const BaseOption& o);
/**
Template class adding type specific behaviour to BaseOption. Define
one of these per program supported option.
@author Dave Flitney
@version 1.0b, Nov., 2000.
@package Options
@see BaseOption
*/
template<class T> class Option: public BaseOption {
public:
/**
@param k Comma seperated list of key aliases
@param v Default value for this option
@param ht Help text to be printed when outputting usage
@param c If true then this option is compulsory
@param f This options argument requirements
*/
Option(const string& k, const T& v, const string& ht,
bool c, ArgFlag f = no_argument):
BaseOption(k, ht, c, f), default_(v), value_(v) {}
/**
@param vs The value string which needs to be parsed to set
this options value. The overloaded function string_to_T must be defined
for type T.
@changes Clears the unset_ flag.
*/
bool set_value(const string& vs) {
if(string_to_T(value_, vs))
unset_ = false;
return !unset_;
}
/**
@return The options value.
*/
const T& value() { return value_; }
/**
@return The options default value.
*/
const T& default_value() { return default_; }
virtual ~Option() {}
private:
Option() {}
T default_, value_;
};
/**
Throw this exception if an error occured inside the Options package.
@package Exceptions
*/
class X_OptionError: public std::exception {
public:
X_OptionError() throw() {};
virtual const char * what() const throw() {
return "There were errors parsing the command line!";
}
};
/**
Throw this exception if no matching option was found during parsing.
@package Exceptions
*/
class X_UnknownOption: public X_OptionError {
public:
X_UnknownOption(const string& s) throw():
str_(s+":unknown option!") {};
virtual const char * what() const throw() {
return str_.c_str();
}
private:
string str_;
};
/**
@package Exceptions
*/
class X_AlreadySet: public X_OptionError {
public:
X_AlreadySet(const string& s) throw():
str_(s+":already set!") {};
virtual const char * what() const throw() {
return str_.c_str();
}
private:
string str_;
};
/**
If an option should have had an argument but didn't then throw this
exception.
@package Exceptions
*/
class X_MissingArgument: public X_OptionError {
public:
X_MissingArgument(const string& s) throw():
str_(s+":missing argument!") {};
virtual const char * what() const throw() {
return str_.c_str();
}
private:
string str_;
};
/**
@package Exceptions
*/
class X_InvalidArgument: public X_OptionError {
public:
X_InvalidArgument(const string& o, const string& v) throw():
str_(o+":invalid argument "+v+"!") {};
virtual const char * what() const throw() {
return str_.c_str();
}
private:
string str_;
};
/**
A class for parsing command line arguments into Option objects.
@author Dave Flitney
@version 1.0b, Nov., 2000.
@package Options
@see BaseOption
@see Option
@example
<pre>
Option<bool> verbose(string("-V,--verbose"), false,
string("switch on diagnostic messages"),
false, no_argument);
Option<bool> help(string("-h,--help"), false,
string("display this message"),
false, no_argument);
Option<float> dof(string("-d,--dof"), 100.0,
string("number of degrees of freedom"),
true, requires_argument);
Option<string> mask(string("-m,--mask"), string("mask"),
string("brain mask volume"),
true, requires_argument);
Option<string> resid(string("-r,--res"), string("res4d"),
string("4d `residual-of-fit' image"),
true, requires_argument);<br>
int main(unsigned int argc, char **argv) {<br>
OptionParser options("options V1.0\nCopyright(c) University of Oxford 2000, Dave Flitney", "options -d <number> --mask <filename> --res <filename>");<br>
try {<br>
options.add(verbose);
options.add(help);
options.add(dof);
options.add(mask);
options.add(resid);<br>
for(unsigned int a = options.parse_command_line(argc, argv); a < argc; a++)
cout << argv[a] << endl;<br>
if(help.value())
options.usage();<br>
if(verbose.value()) {
cout << "verbose = " << verbose.value() << endl;
cout << "help = " << help.value() << endl;
cout << "dof = " << dof.value() << endl;
cout << "mask = " << mask.value() << endl;
cout << "resid = " << resid.value() << endl;
}<br>
} catch(X_OptionError& e) {
options.usage();
cerr << endl << e.what() << endl;
} catch(std::exception &e) {
cerr << e.what() << endl;
}
}
</pre>
*/
class OptionParser {
public:
static OptionParser* Instance();
/**
@param o An option to be added to the parser
*/
void add(const string& key, BaseOption& o) { options_[key] = &o; }
void usage(const string& p, const string& e);
/**
@param verbose If set then this method will carp about any option which
is marked as compulsory but hasn't been set
@return true if all compulsory arguments have been set and false otherwise
*/
bool check_compulsory_arguments(bool verbose=false);
/**
The parameters, argc and argv, should normally be those passed to
main via the command line shell.
@param argc The argument count.
@param argv The vector of argument strings.
*/
unsigned int parse_command_line(unsigned int argc, char **argv);
BaseOption* operator () (const string& key) { return options_[key]; }
virtual ~OptionParser() {}
protected:
/**
*/
OptionParser() {}
private:
/**
@param optstr A string which should match one of the option strings
registered with the add method.
@return Pointer to the matching option or NULL if a match wasn't found.
*/
BaseOption* find_matching_option(const string& optstr);
/**
@param optstr A string which should match one of the option strings
registered with the add method.
@param valstr A string which can be used to set the options value
if applicable.
@return true on success.
*/
unsigned int parse_option(const string& optstr, const string& valstr)
throw(X_AlreadySet, X_UnknownOption,
X_MissingArgument, X_InvalidArgument);
/**
@param str A string of the form --option[=value].
@return true on success.
*/
unsigned int parse_long_option(const string& str);
static OptionParser *instance_;
typedef map<string, BaseOption *> Options;
Options options_;
};
}
#endif