src/optparse/optparse.cpp

Go to the documentation of this file.
00001 /*
00002  * Implementation of optparse.h
00003  * 
00004  * Roman Geus, 2005
00005  *
00006  */
00007 
00008 #include <iostream>
00009 #include <sstream>
00010 #include "optparse.h"
00011 
00012 using namespace std;
00013 
00014 namespace optparse {
00015 
00016 /********************** Option **********************/
00017 
00018 Option::Option (string shrt, string lng, string dest,
00019                 string hlp, action_t act, string dfault, type_t type, string allowed_args)
00020         : action (act),
00021         shrt_flag (shrt),
00022         lng_flag (lng),
00023         help (hlp),
00024         destination (dest),
00025         dfault_(dfault),
00026         type_(type),
00027         allowed_args_(allowed_args)
00028 {}
00029 
00030 Option::~Option () {}
00031 
00032 bool 
00033 Option::is_allowed(std::string argument) {
00034     // Test type
00035     // FIXME: implement that
00036     
00037     // Test allowed values
00038     if (allowed_args_ == "")
00039         return true;
00040     
00041     size_t pos_begin = 0;
00042     do {
00043         size_t pos_comma = allowed_args_.find(',', pos_begin);
00044         if (pos_comma == string::npos)
00045             pos_comma = allowed_args_.size();
00046         if (allowed_args_.substr(pos_begin, pos_comma-pos_begin) == argument)
00047             return true;
00048         pos_begin = pos_comma + 1;
00049     } while(pos_begin < allowed_args_.size());    
00050     return false;
00051 }
00052 
00053 /******************** OptionParser *******************/
00054 
00055 OptionParser::OptionParser (string usage)
00056     : use_msg (usage) 
00057 { }
00058 
00059 OptionParser::~OptionParser () {}
00060 
00061 void
00062 OptionParser::add_option(string shrt_flag, string lng_flag, string destination,
00063                          string help, action_t act, type_t type, string dfault,
00064                          string allowed_values) 
00065 {
00066     Option option(shrt_flag, lng_flag, destination, help, act, dfault, type, allowed_values);
00067     
00068     /* Add the option to our list of options. */
00069     opts.push_back(option);
00070 
00071     /* Set the default value for this option, this not only allows you to
00072      * set default values but insures that every option's destination will
00073      * be in our dictionary, even if the value is only "".
00074      */
00075     set_option(option, dfault);
00076 }
00077 
00078 void
00079 OptionParser::parse_args (int argc, char **argv) {
00080     /* Walk through the arguments and sort them into options
00081      * or arguments.
00082      */
00083     for (int i = 1; i < argc; i++) {
00084         /* If we start with a '-' we're probably a <flag><value> pair
00085          * so we need to figure out which option it is. find_opt() is
00086          * where the real work is done.
00087          */
00088         if (argv[i][0] == '-')
00089             if (argv[i][1] == '-')
00090                 find_opt_long(argc, argv, i);
00091             else
00092                 find_opt_short(argc, argv, i);
00093 
00094         /* If we're looking at an argument (i.e. a value with no flag who's
00095          * meaning is determined by position) just append it into the
00096          * arguments list.
00097          */
00098         else
00099             arguments.insert(arguments.end(), argv[i]);
00100     }
00101 }
00102 
00103 void
00104 OptionParser::help (ostream& os) {
00105     const size_t WORD_WRAP = 50;      // max width of last column
00106     
00107     // Determine column width for short options
00108     size_t shrt_flag_max_len = 0;
00109     for (size_t i=0; i < opts.size(); ++ i) {
00110         stringstream buf;
00111         buf << opts[i].shrt_flag;
00112         if (opts[i].shrt_flag != "" && opts[i].action == STORE)
00113             buf << " " << type2string(opts[i].type_);
00114         if (buf.str().size() > shrt_flag_max_len)
00115             shrt_flag_max_len = buf.str().size();
00116     }
00117     
00118     // Determine column width for long options
00119     size_t lng_flag_max_len = 0;
00120     for (size_t i=0; i < opts.size(); ++ i) {
00121         stringstream buf;
00122         buf << opts[i].lng_flag;
00123         if (opts[i].action == STORE)
00124             buf << "=" << type2string(opts[i].type_);
00125         if (buf.str().size() > lng_flag_max_len)
00126             lng_flag_max_len = buf.str().size();
00127     }
00128     
00129     os << use_msg << endl;
00130     for (size_t i=0; i < opts.size(); ++ i) {
00131         stringstream line;
00132         line << "  ";
00133         
00134         // short option column
00135         stringstream shrt_buf;
00136         shrt_buf << opts[i].shrt_flag;
00137         if (opts[i].shrt_flag != "" && opts[i].action == STORE)
00138             shrt_buf << " " << type2string(opts[i].type_);
00139         line << ' ' << shrt_buf.str();
00140         for (size_t k = 0; k < shrt_flag_max_len-shrt_buf.str().size()+2; ++ k)
00141             line << ' ';
00142             
00143         // long option column
00144         stringstream buf;
00145         buf << opts[i].lng_flag;
00146         if (opts[i].action == STORE)
00147             buf << "=" << type2string(opts[i].type_);        
00148         line << buf.str();
00149         for (size_t k = 0; k < lng_flag_max_len-buf.str().size()+4; ++ k)
00150             line << ' ';
00151         
00152         // help column
00153         os << line.str();
00154         size_t help_col = line.str().size();
00155         line.str("");
00156         
00157         line << opts[i].help;
00158         bool is_allowed = opts[i].allowed_args_ != "";
00159         bool is_default = opts[i].action == STORE && opts[i].dfault_ != "";
00160         if (is_allowed || is_default) {
00161             line << " (";
00162             if (is_allowed) {
00163                 line << "possible values=";
00164                 size_t pos_begin = 0;
00165                 size_t pos_comma = opts[i].allowed_args_.find(',', pos_begin);
00166                 while (pos_comma != string::npos) {
00167                     line << '\'' << opts[i].allowed_args_.substr(pos_begin, pos_comma-pos_begin) << "\',";
00168                     pos_begin = pos_comma + 1;
00169                     pos_comma = opts[i].allowed_args_.find(',', pos_begin);
00170                 }
00171                 line << '\'' << opts[i].allowed_args_.substr(pos_begin) << '\'';
00172                 if (is_default)
00173                     line << ", ";
00174             }
00175             if (is_default)
00176                 line << "default=\'" << opts[i].dfault_ << "\'";
00177             line << ')';
00178         }
00179         
00180         // split over several lines
00181         size_t begin_pos = 0;
00182         size_t last_pos = 0;
00183         size_t next_pos;
00184         
00185         do {        
00186             next_pos = line.str().find_first_of(" ,", last_pos+1);
00187             if (next_pos == string::npos)
00188                 next_pos = line.str().size()-1;
00189             if (last_pos == line.str().size()-1 || (next_pos+1 - begin_pos > WORD_WRAP && last_pos > begin_pos)) {
00190                 if (begin_pos != 0)
00191                     for (size_t k = 0; k < help_col+2; ++ k)
00192                         os << ' ';
00193                 os << line.str().substr(begin_pos, last_pos+1 - begin_pos) << endl;
00194                 begin_pos = last_pos+1;
00195                 last_pos = begin_pos;
00196             } else
00197                 last_pos = next_pos;
00198         } while (begin_pos != line.str().size());
00199     }        
00200  }
00201 
00202 void
00203 OptionParser::find_opt_short(int argc, char **argv, int &index) {
00204     /* Step through our list of known options. */
00205     for (size_t i = 0; i < opts.size(); i++) {
00206         /* Uses the overridden == operator for the Options class
00207          * to compare argv[index] to the flags of each Option.
00208          */
00209         if (opts[i].shrt_flag == (string)argv[index]) {
00210             switch (opts[i].action) {
00211             case STORE_FALSE:
00212                 set_option(opts[i], "0");
00213                 break;
00214             case STORE_TRUE:
00215                 set_option(opts[i], "1");
00216                 break;
00217             case STORE:
00218                 /* Set the value and return if we've found a match. */
00219                 if (index >= argc-1)
00220                     throw OptionError(argv[index], "Missing option argument");
00221                 set_option(opts[i], argv[index+1]);
00222                 index++;                
00223                 break;
00224             default:
00225                 break;
00226             };
00227             return;
00228         }
00229     }
00230     
00231     /* If we haven't found a match this is not a known argument. */
00232     throw OptionError(argv[index], "Unknown option");
00233 }
00234 
00235 void
00236 OptionParser::find_opt_long(int argc, char **argv, int &index) {
00237     // Split option and argument at "="
00238     string option;
00239     string argument;
00240     string arg_str(argv[index]);
00241     size_t equal_pos = arg_str.find('=');
00242     if (equal_pos != string::npos) {
00243         option = arg_str.substr(0, equal_pos);
00244         argument = arg_str.substr(equal_pos+1, string::npos);
00245     } else
00246         option = arg_str;
00247     
00248     /* Step through our list of known options. */
00249     for (size_t i = 0; i < opts.size(); i++) {
00250         if (opts[i].lng_flag == option) {
00251             switch (opts[i].action) {
00252             case STORE_FALSE:
00253                 if (argument != "")
00254                     throw OptionError(option, "No argument expected for this option");
00255                 set_option(opts[i], "0");
00256                 break;
00257             case STORE_TRUE:
00258                 if (argument != "")
00259                     throw OptionError(option, "No argument expected for this option");
00260                 set_option(opts[i], "1");
00261                 break;
00262             case STORE:
00263                 if (argument == "")
00264                     throw OptionError(option, "Missing option argument");
00265                 set_option(opts[i], argument);
00266                 break;
00267             default:
00268                 break;
00269             };
00270             return;
00271         }
00272     }
00273     
00274     /* If we haven't found a match this is not a known argument. */
00275     throw OptionError(option, "Unknown option");
00276 }
00277 
00278 void OptionParser::set_option(Option& option, std::string argument) {
00279     if (option.is_allowed(argument))
00280         options[option.destination] = argument;
00281     else
00282         throw OptionError("", "Invalid argument for option");
00283 }
00284 
00285 string OptionParser::type2string(type_t type) {
00286     if (type == STRING)
00287         return string("STRING");
00288     else if (type == DOUBLE)
00289         return string("DOUBLE");
00290     else if (type == INT)
00291         return string("INT");
00292     else if (type == BOOL)
00293         return string("BOOL");
00294     else
00295         return "";
00296 }
00297 
00298 } // namespace optparse

Generated on Fri Oct 26 13:35:12 2007 for FEMAXX (Finite Element Maxwell Eigensolver) by  doxygen 1.4.7