// $Id$ #if !defined(OPTIONS_H) #define OPTIONS_H #include <stdexcept> #include <string> #include <vector> #define POSIX_SOURCE 1 namespace Options { 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 void value(const string& vs) = 0; virtual ~BaseOption() {} private: string key_, help_text_; ArgFlag arg_flag_; protected: bool unset_, compulsory_; }; void string_to_T(bool &b, const string& s); void string_to_T(string& d, const string& s); void string_to_T(int& i, const string& s); void string_to_T(float& v, const string& s); /** 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. */ void value(const string& vs) { string_to_T(value_, vs); unset_ = false; } /** @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_UnknownOptions: public X_OptionError { public: X_UnknownOptions() throw() {}; virtual const char * what() const throw() { return "There were unknown options!"; } }; /** If an option should have had an argument but didn't then throw this exception. @package Exceptions */ class X_MissingArguments: public X_OptionError { public: X_MissingArguments() throw() {}; virtual const char * what() const throw() { return "There were missing arguments!"; } }; /** 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: /** @param p The program identifier string @param e Example usage string */ OptionParser(const string& p, const string& e): progname_(p), example_(e) {} /** @param o An option to be added to the parser */ void add(BaseOption& o) { options_.push_back(&o); } void usage(); /** @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) throw(X_OptionError, X_UnknownOptions, X_MissingArguments); ~OptionParser() {} private: unsigned int argc_; char **argv_; string progname_, example_; typedef vector<BaseOption *> Options; Options options_; }; } #endif