diff --git a/options.cc b/options.cc index 59d2fde0c00afa2aaec4727f9f260268f4b724b7..2571b5bc66b7df283f5d9b11d19d4da2278c26e1 100644 --- a/options.cc +++ b/options.cc @@ -1,207 +1,227 @@ #include "options.h" -void string_to_T(bool &b, const string& s) { - if(s == "NO ARG") - b = !b; - else - b = (s == "true"); -} +namespace Options { -void string_to_T(string& d, const string& s) { - d = s; -} + void string_to_T(bool &b, const string& s) { + if(s == "NO ARG") + b = !b; + else + b = (s == "true"); + } -void string_to_T(int& i, const string& s) { - i = atoi(s.c_str()); -} + void string_to_T(string& d, const string& s) { + d = s; + } -void string_to_T(float& v, const string& s) { - v = atof(s.c_str()); -} + void string_to_T(int& i, const string& s) { + i = atoi(s.c_str()); + } + + void string_to_T(float& v, const string& s) { + v = atof(s.c_str()); + } -bool BaseOption::matches(const string& arg) -{ - string::size_type pos = 0, np; - while((np = key_.find(",", pos)) != string::npos) { - if(arg == key_.substr(pos, np - pos)) + bool BaseOption::matches(const string& arg) + { + string::size_type pos = 0, np; + while((np = key_.find(",", pos)) != string::npos) { + if(arg == key_.substr(pos, np - pos)) + return true; + pos = np + 1; + } + if(arg == key_.substr(pos, string::npos)) return true; - pos = np + 1; + return false; } - if(arg == key_.substr(pos, string::npos)) - return true; - return false; -} -ostream& operator<<(ostream &os, const BaseOption& o) { - return os << - "\t" << o.key() << - "\t" << o.help_text(); -} + ostream& operator<<(ostream &os, const BaseOption& o) { + return os << + "\t" << o.key() << + "\t" << o.help_text(); + } -void OptionParser::usage() -{ - cerr << endl << progname_ << endl << endl; - cerr << "Usage: " << endl << example_ << endl; - - for(Options::iterator option = options_.begin(); option != options_.end(); - option++) - { - if((*option)->compulsory()) { - static bool banner = true; - if(banner) { - cerr << endl << "Compulsory arguments (You MUST set one or more of):" << endl; - banner = false; + void OptionParser::usage() + { + cerr << endl << progname_ << endl << endl; + cerr << "Usage: " << endl << example_ << endl; + + for(Options::iterator option = options_.begin(); option != options_.end(); + option++) + { + if((*option)->compulsory()) { + static bool banner = true; + if(banner) { + cerr << endl << "Compulsory arguments (You MUST set one or more of):" << endl; + banner = false; + } + cerr << **option << endl; } - cerr << **option << endl; } - } - for(Options::iterator option = options_.begin(); option != options_.end(); - option++) - { - if(!(*option)->compulsory()) { - static bool banner = true; - if(banner) { - cerr << endl << "Optional arguments (You may optionally specify one or more of):" << endl; - banner = false; + for(Options::iterator option = options_.begin(); option != options_.end(); + option++) + { + if(!(*option)->compulsory()) { + static bool banner = true; + if(banner) { + cerr << endl << "Optional arguments (You may optionally specify one or more of):" << endl; + banner = false; + } + cerr << **option << endl; } - cerr << **option << endl; } - } - cerr << endl; - cerr << endl; -} + cerr << endl; + cerr << endl; + } -bool OptionParser::check_compulsory_arguments(bool verbose) -{ - bool okay = true; + bool OptionParser::check_compulsory_arguments(bool verbose) + { + bool okay = true; - for(Options::iterator option = options_.begin(); - option != options_.end(); - option++) { + for(Options::iterator option = options_.begin(); + option != options_.end(); + option++) { - if((*option)->compulsory() && (*option)->unset()) { - if(okay) { - if(verbose) { - cerr << "***************************************************" << endl; - cerr << "The following COMPULSORY options have not been set:" << endl; + if((*option)->compulsory() && (*option)->unset()) { + if(okay) { + if(verbose) { + cerr << "***************************************************" << endl; + cerr << "The following COMPULSORY options have not been set:" << endl; + } + okay = false; } - okay = false; + if(verbose) + cerr << **option << endl; } - if(verbose) - cerr << **option << endl; } - } - if(!okay && verbose) - cerr << "***************************************************" << endl; + if(!okay && verbose) + cerr << "***************************************************" << endl; - return okay; -} - -unsigned int OptionParser::parse_command_line(unsigned int argc, - char **argv) -{ - unsigned int argcount = 1; - bool usage_needed = false; + return okay; + } - while(argcount < argc) { - unsigned int nmatches = 0; - unsigned int increments = 1; + unsigned int OptionParser::parse_command_line(unsigned int argc, + char **argv) + throw(X_OptionError, X_UnknownOptions, X_MissingArguments) + { + unsigned int argcount = 1; + bool unknown_opts = false; + bool missing_args = false; + + while(argcount < argc) { + unsigned int nmatches = 0; + unsigned int increments = 1; - string optstr(argv[argcount]), valstr; - if(argcount + 1 < argc) - valstr = string(argv[argcount+1]); - else - valstr = string("NO ARG"); - if(optstr[0] != '-') // No more parsable options - break; - - for(Options::iterator option = options_.begin(); - option != options_.end(); - option++) { - if((*option)->matches(optstr)) - { - nmatches++; - if((*option)->required()) { - if(valstr != "NO ARG") { - (*option)->value(valstr); - increments = 2; - } else { - cerr << optstr << " : Missing argument!" << endl; - usage_needed = true; - } - } else if((*option)->optional()) { - if(valstr[0] != '-') { - (*option)->value(valstr); - increments = 2; + string optstr(argv[argcount]), valstr; + if(argcount + 1 < argc) + valstr = string(argv[argcount+1]); + else + valstr = string("NO ARG"); + if(optstr[0] != '-') // No more parsable options + break; + + for(Options::iterator option = options_.begin(); + option != options_.end(); + option++) { + if((*option)->matches(optstr)) + { + nmatches++; + if((*option)->required()) { + if(valstr != "NO ARG") { + (*option)->value(valstr); + increments = 2; + } else { + cerr << optstr << ": missing argument!" << endl; + missing_args = true; + } + } else if((*option)->optional()) { + if(valstr[0] != '-') { + (*option)->value(valstr); + increments = 2; + } else { + (*option)->value("NO ARG"); + } } else { (*option)->value("NO ARG"); } - } else { - (*option)->value("NO ARG"); } - } - } - if(nmatches == 0) { - cerr << optstr << " : Unknown option!" << endl; - usage_needed = true; + } + if(nmatches == 0) { + cerr << optstr << ": unknown option!" << endl; + unknown_opts = true; + } + argcount += increments; } - argcount += increments; + + if(unknown_opts && missing_args) + throw X_OptionError(); + else if(unknown_opts) + throw X_UnknownOptions(); + else if(missing_args) + throw X_MissingArguments(); + + return argcount; // User should process any remaining args } - return argcount; // User should process any remaining args } - - - // // And now for the test stub... // #if defined(TESTING) +using namespace Opts; + Option<bool> verbose(string("-V,--verbose"), false, string("switch on diagnostic messages"), - false, BaseOption::no_argument); + false, no_argument); Option<bool> help(string("-h,--help"), false, string("display this message"), - false, BaseOption::no_argument); + false, no_argument); Option<float> dof(string("-d,--dof"), 100.0, string("number of degrees of freedom"), - true, BaseOption::requires_argument); + true, requires_argument); Option<string> mask(string("-m,--mask"), string("mask"), string("brain mask volume"), - true, BaseOption::requires_argument); + true, requires_argument); Option<string> resid(string("-r,--res"), string("res4d"), string("4d `residual-of-fit' image"), - true, BaseOption::requires_argument); + true, requires_argument); int main(unsigned int argc, char **argv) { OptionParser options("options", "-d <number> --mask <filename> --res <filename>"); - options.add(verbose); - options.add(help); - options.add(dof); - options.add(mask); - options.add(resid); + try { - for(unsigned int a = options.parse_command_line(argc, argv); a < argc; a++) - cout << argv[a] << endl; - - if(help.value()) - options.usage(); + options.add(verbose); + options.add(help); + options.add(dof); + options.add(mask); + options.add(resid); - 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; - } + for(unsigned int a = options.parse_command_line(argc, argv); a < argc; a++) + cout << argv[a] << endl; + + if(help.value()) + options.usage(); + + 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; + } + } catch(X_OptionError& e) { + options.usage(); + cerr << endl << e.what() << endl; + } catch(std::exception &e) { + cerr << e.what() << endl; + } } #endif