00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef OPTIONMM_command_line
00023 #define OPTIONMM_command_line
00024 #ifndef OPTIONMM_optionmm
00025 #include <optionmm/option.hh>
00026 #endif
00027 #ifndef __VECTOR__
00028 #include <vector>
00029 #endif
00030 #ifndef __STRING__
00031 #include <string>
00032 #endif
00033 #ifndef __IOSTREAM__
00034 #include <iostream>
00035 #endif
00036
00037
00038
00039
00040
00041
00042 namespace optionmm
00043 {
00044
00045
00046
00047
00048
00049
00050 struct default_error_handler
00051 {
00052
00053
00054
00055
00056
00057 bool on_unknown(char c, const std::string& progname)
00058 {
00059 std::cerr << "Option `-" << c << "' unknown, try `"
00060 << progname << " --help'" << std::endl;
00061 return true;
00062 }
00063
00064
00065
00066
00067
00068 bool on_unknown(const std::string& str, const std::string& progname)
00069 {
00070 std::cerr << "Option `" << str << "' unknown, try `"
00071 << progname << " --help'" << std::endl;
00072 return true;
00073 }
00074
00075
00076
00077
00078
00079
00080
00081 template <typename Option>
00082 bool on_missing_argument(Option& o,
00083 bool is_short,
00084 const std::string& progname)
00085 {
00086 std::cerr << "Option ";
00087 if (is_short) std::cerr << "-" << o.short_name();
00088 else std::cerr << "--" << o.long_name();
00089 std::cerr << " need an argument, try " << progname << " --help"
00090 << std::endl;
00091 return true;
00092 }
00093
00094
00095
00096
00097
00098
00099
00100 template <typename Option>
00101 bool on_bad_argument(Option& o,
00102 bool is_short,
00103 const std::string& progname)
00104 {
00105 std::cerr << "Bad argument to option ";
00106 if (is_short) std::cerr << "-" << o.short_name();
00107 else std::cerr << "--" << o.long_name();
00108 std::cerr << ", try " << progname << " --help" << std::endl;
00109 return true;
00110 }
00111 };
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 template <typename ErrorHandler=default_error_handler>
00142 class basic_command_line : public ErrorHandler
00143 {
00144 public:
00145
00146 typedef std::vector<option_base*> option_list;
00147 private:
00148
00149 option_list _options;
00150
00151 std::string _program_name;
00152
00153 int& _argc;
00154
00155 char** _argv;
00156
00157 std::string _title;
00158
00159 std::string _version;
00160
00161 std::string _copyright;
00162
00163 std::string _usage;
00164
00165 basic_option<bool,false,false> _help_option;
00166
00167 basic_option<bool,false,false> _version_option;
00168
00169
00170 bool handle_short(int& i);
00171
00172
00173 bool handle_long(int& i);
00174
00175 void cleanup();
00176 public:
00177
00178
00179
00180
00181
00182
00183
00184
00185 basic_command_line(const std::string title,
00186 const std::string& version,
00187 const std::string& copy,
00188 const std::string& usage,
00189 int& argc,
00190 char** argv);
00191
00192
00193 template <typename T, bool a, bool m>
00194 void add(basic_option<T,a,m>& option) { _options.push_back(&option); }
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 bool help(std::ostream& o=std::cout);
00212
00213
00214
00215
00216
00217 bool version(std::ostream& o=std::cout);
00218
00219
00220 bool process();
00221
00222 const std::string& program_name() const { return _program_name; }
00223
00224 const std::string& title() const { return _title; }
00225
00226 const std::string& version() const { return _title; }
00227
00228 const std::string& copyright() const { return _copyright; }
00229 };
00230
00231
00232 template <typename ErrorHandler>
00233 inline
00234 basic_command_line<ErrorHandler>::
00235 basic_command_line(const std::string title,
00236 const std::string& version,
00237 const std::string& copy,
00238 const std::string& usage,
00239 int& argc,
00240 char** argv)
00241 : _program_name(argv[0]),
00242 _argc(argc),
00243 _argv(argv),
00244 _title(title),
00245 _version(version),
00246 _copyright(copy),
00247 _usage(usage),
00248 _help_option('h',"help","Show this help",false),
00249 _version_option('\0',"version", "Show version information",false)
00250 {
00251 std::string::size_type slash = _program_name.find_last_of('/');
00252 _program_name.erase(0, slash+1);
00253 add(_help_option);
00254 add(_version_option);
00255 }
00256
00257
00258 template <typename ErrorHandler>
00259 inline
00260 bool
00261 basic_command_line<ErrorHandler>::help(std::ostream& out)
00262 {
00263 if (!_help_option.value()) return false;
00264
00265 _version_option.push_arg(_help_option.position());
00266 version();
00267 out << std::endl << "Usage: " << _program_name;
00268 if (_usage.empty()) out << " [OPTIONS]";
00269 else out << " " << _usage;
00270 out << std::endl << std::endl;
00271
00272
00273 int ll = 0;
00274 for (option_list::iterator o = _options.begin(); o != _options.end(); ++o)
00275 if ((*o)->long_name().length() >= ll) ll = (*o)->long_name().length();
00276 for (option_list::iterator p = _options.begin();
00277 p != _options.end(); ++p) {
00278 out << " ";
00279 (*p)->print(ll, out);
00280 out << std::endl;
00281 }
00282 out << std::endl;
00283 return true;
00284 }
00285
00286
00287 template <typename ErrorHandler>
00288 inline
00289 bool
00290 basic_command_line<ErrorHandler>::version(std::ostream& o)
00291 {
00292 if (!_version_option.value()) return false;
00293 o << _title << " version " << _version << std::endl
00294 << _copyright << std::endl;
00295 return true;
00296 }
00297
00298
00299 template <typename ErrorHandler>
00300 inline
00301 bool
00302 basic_command_line<ErrorHandler>::process()
00303 {
00304 for (int i = 1; i < _argc; i++) {
00305 if (_argv[i] && _argv[i][0] == '-') {
00306
00307 bool ret;
00308 if (_argv[i][1] != '-') ret = handle_short(i);
00309 else ret = handle_long(i);
00310 if (!ret) return false;
00311 }
00312 }
00313 cleanup();
00314 return true;
00315 }
00316
00317
00318 template <typename ErrorHandler>
00319 inline
00320 void
00321 basic_command_line<ErrorHandler>::cleanup()
00322 {
00323 int n = 1;
00324 for (int i = 1; i < _argc; i++) {
00325 int j = i;
00326 while (!_argv[j] && j < _argc-1) { j++; }
00327 if (i != j) {
00328 _argv[i] = _argv[j];
00329 _argv[j] = 0;
00330 }
00331 if (_argv[i]) n++;
00332 }
00333 _argc = n;
00334 }
00335
00336
00337
00338 template <typename ErrorHandler>
00339 inline
00340 bool
00341 basic_command_line<ErrorHandler>::handle_short(int& i)
00342 {
00343 int j = 1;
00344 int ret = 0;
00345 bool gotit = false;
00346 while (_argv[i] && _argv[i][j] && _argv[i][j] != '-') {
00347 option_list::iterator o;
00348 for (o = _options.begin(); o < _options.end(); o++) {
00349 char* arg = &(_argv[i][j]);
00350 if ((ret = (*o)->handle(arg, _argv[i+1], i))
00351 == option_base::can_handle) {
00352 int k = j;
00353
00354 while (_argv[i][k] != '\0') {
00355
00356
00357
00358
00359 _argv[i][k] = _argv[i][k+1];
00360 k++;
00361 }
00362 j--;
00363 if (!_argv[i+1]) gotit = true;
00364 break;
00365 }
00366 switch (ret) {
00367 case option_base::bad_argument:
00368 if (ErrorHandler::on_bad_argument(**o, true, _program_name))
00369 return false;
00370 break;
00371 case option_base::missing_argument:
00372 if (ErrorHandler::on_missing_argument(**o, true, _program_name))
00373 return false;
00374 break;
00375 }
00376 }
00377 if (gotit) break;
00378 if (o == _options.end())
00379 if (ErrorHandler::on_unknown(_argv[i][j], _program_name))
00380 return false;
00381 j++;
00382 }
00383 if (_argv[i][0] == '-' && _argv[i][1] == '\0') _argv[i] = 0;
00384 if (gotit) i++;
00385 return true;
00386 }
00387
00388
00389 template <typename ErrorHandler>
00390 inline
00391 bool
00392 basic_command_line<ErrorHandler>::handle_long(int& i)
00393 {
00394 int ret = 0;
00395 std::string n(_argv[i]);
00396 option_list::iterator o;
00397 for (o = _options.begin(); o < _options.end(); o++) {
00398 if ((ret = (*o)->handle(n, i)) == option_base::can_handle) {
00399 _argv[i] = 0;
00400 break;
00401 }
00402 switch (ret) {
00403 case option_base::bad_argument:
00404 if (ErrorHandler::on_bad_argument(**o, false, _program_name))
00405 return false;
00406 break;
00407 case option_base::missing_argument:
00408 if (ErrorHandler::on_missing_argument(**o, false, _program_name))
00409 return false;
00410 break;
00411 }
00412 }
00413 if (o == _options.end())
00414 if (ErrorHandler::on_unknown(n, _program_name))
00415 return false;
00416 return true;
00417 }
00418
00419
00420
00421 typedef basic_option<int,true,true> int_option;
00422
00423
00424 typedef basic_option<float,true,true> float_option;
00425
00426
00427 typedef basic_option<bool,false,false> bool_option;
00428
00429
00430 typedef basic_option<std::string,true,true> string_option;
00431
00432
00433 typedef basic_command_line<> command_line;
00434 }
00435
00436 #endif
00437
00438
00439
00440