00001
00002
00003
00004
00005
00006
00007
00008 #include <iostream>
00009 #include <sstream>
00010 #include "optparse.h"
00011
00012 using namespace std;
00013
00014 namespace optparse {
00015
00016
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
00035
00036
00037
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
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
00069 opts.push_back(option);
00070
00071
00072
00073
00074
00075 set_option(option, dfault);
00076 }
00077
00078 void
00079 OptionParser::parse_args (int argc, char **argv) {
00080
00081
00082
00083 for (int i = 1; i < argc; i++) {
00084
00085
00086
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
00095
00096
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;
00106
00107
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
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
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
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
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
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
00205 for (size_t i = 0; i < opts.size(); i++) {
00206
00207
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
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
00232 throw OptionError(argv[index], "Unknown option");
00233 }
00234
00235 void
00236 OptionParser::find_opt_long(int argc, char **argv, int &index) {
00237
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
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
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 }