Skip to content
Snippets Groups Projects
options.cc 3.79 KiB
#include "options.h"

namespace Options {

  void string_to_T(bool &b, const string& s) {
    if(s == "NO ARG")
      b = !b;
    else
      b = (s == "true");
  }

  void string_to_T(string& d, const string& s) {
    d = s;
  }

  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))
	return true;
      pos = np + 1;
    }
    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();
  }

  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;
	}
      }


    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 << endl;
    cerr << endl;
  }

  bool OptionParser::check_compulsory_arguments(bool verbose)
  {
    bool okay = true;

    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;
	  }
	  okay = false;
	}
	if(verbose)
	  cerr << **option << endl;
      }
    }
    if(!okay && verbose)
      cerr << "***************************************************" << endl; 

    return okay;
  }

  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;
		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");
	    }
	  }
      }
      if(nmatches == 0) {
	cerr << optstr << ": unknown option!" << endl;
	unknown_opts = true;
      }
      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
  }

}