00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <utilities/Argument_helper.h>
00018
00019
00020 #include <iostream>
00021 #include <cstdlib>
00022 #include <cstdio>
00023
00024 #include <cassert>
00025
00026
00027
00028 namespace dsr {
00029
00030 bool verbose=false, VERBOSE=false;
00031
00032
00034
00035
00036
00037
00038
00039 class Argument_helper::Argument_target {
00040 public:
00041 char key;
00042 std::string long_name;
00043 std::string description;
00044 std::string arg_description;
00045
00046 Argument_target(char k, const std::string lname,
00047 const std::string descr,
00048 const std::string arg_descr) {
00049 key=k;
00050 long_name=lname;
00051 description=descr;
00052 arg_description=arg_descr;
00053 }
00054 Argument_target(const std::string descr,
00055 const std::string arg_descr) {
00056 key=0;
00057 long_name="";
00058 description=descr;
00059 arg_description=arg_descr;
00060 }
00061 virtual bool process(int &, const char **&)=0;
00062 virtual void write_name(std::ostream &out) const;
00063 virtual void write_value(std::ostream &out) const=0;
00064 virtual void write_usage(std::ostream &out) const;
00065 virtual ~Argument_target(){}
00066 };
00067
00068 void Argument_helper::Argument_target::write_name(std::ostream &out) const {
00069 if (key != 0) out << '-' << key;
00070 else if (!long_name.empty()) out << "--" << long_name;
00071 else out << arg_description;
00072 }
00073
00074
00075 void Argument_helper::Argument_target::write_usage(std::ostream &out) const {
00076 if (key != 0) {
00077 out << '-' << key;
00078 out << "/--" << long_name;
00079 }
00080 out << ' ' << arg_description;
00081 out << "\t" << description;
00082 out << " Value: ";
00083 write_value(out);
00084 out << std::endl;
00085 }
00086
00087 class Argument_helper::FlagTarget: public Argument_helper::Argument_target{
00088 public:
00089 bool &val;
00090 FlagTarget(char k, const char *lname,
00091 const char *descr,
00092 bool &b): Argument_target(k, std::string(lname), std::string(descr),
00093 std::string()), val(b){}
00094 virtual bool process(int &, const char **&){
00095 val= !val;
00096 return true;
00097 }
00098 virtual void write_value(std::ostream &out) const {
00099 out << val;
00100 }
00101
00102 virtual void write_usage(std::ostream &out) const {
00103 if (key != 0) {
00104 out << '-' << key;
00105 out << "/--" << long_name;
00106 }
00107 out << "\t" << description;
00108 out << " Value: ";
00109 write_value(out);
00110 out << std::endl;
00111 }
00112 virtual ~FlagTarget(){}
00113 };
00114
00115 class Argument_helper::DoubleTarget: public Argument_target{
00116 public:
00117 double &val;
00118 DoubleTarget(char k, const char *lname,
00119 const char *arg_descr,
00120 const char *descr, double &b): Argument_target(k, std::string(lname),
00121 std::string(descr),
00122 std::string(arg_descr)), val(b){}
00123 DoubleTarget(const char *arg_descr,
00124 const char *descr, double &b): Argument_target(std::string(descr),
00125 std::string(arg_descr)), val(b){}
00126 virtual bool process(int &argc, const char **&argv){
00127 if (argc==0){
00128 std::cerr << "Missing value for argument." << std::endl;
00129 return false;
00130 }
00131 if (sscanf(argv[0], "%le", &val) ==1){
00132 --argc;
00133 ++argv;
00134 return true;
00135 } else {
00136 std::cerr << "Double not found at " << argv[0] << std::endl;
00137 return false;
00138 }
00139 }
00140 virtual void write_value(std::ostream &out) const {
00141 out << val;
00142 }
00143 virtual ~DoubleTarget(){}
00144 };
00145
00146 class Argument_helper::IntTarget: public Argument_target{
00147 public:
00148 int &val;
00149 IntTarget(const char *arg_descr,
00150 const char *descr, int &b): Argument_target(0, std::string(),
00151 std::string(descr),
00152 std::string(arg_descr)),
00153 val(b){}
00154 IntTarget(char k, const char *lname,
00155 const char *arg_descr,
00156 const char *descr, int &b): Argument_target(k, std::string(lname),
00157 std::string(descr),
00158 std::string(arg_descr)),
00159 val(b){}
00160 virtual bool process(int &argc, const char **&argv){
00161 if (argc==0){
00162 std::cerr << "Missing value for argument." << std::endl;
00163 return false;
00164 }
00165 if (sscanf(argv[0], "%d", &val) ==1){
00166 --argc;
00167 ++argv;
00168 return true;
00169 } else {
00170 std::cerr << "Integer not found at " << argv[0] << std::endl;
00171 return false;
00172 }
00173 }
00174 virtual void write_value(std::ostream &out) const {
00175 out << val;
00176 }
00177 virtual ~IntTarget(){}
00178 };
00179
00180 class Argument_helper::UIntTarget: public Argument_target{
00181 public:
00182 unsigned int &val;
00183 UIntTarget(const char *arg_descr,
00184 const char *descr, unsigned int &b): Argument_target(0, std::string(),
00185 std::string(descr),
00186 std::string(arg_descr)),
00187 val(b){}
00188 UIntTarget(char k, const char *lname,
00189 const char *arg_descr,
00190 const char *descr, unsigned int &b): Argument_target(k, std::string(lname),
00191 std::string(descr),
00192 std::string(arg_descr)),
00193 val(b){}
00194 virtual bool process(int &argc, const char **&argv){
00195 if (argc==0){
00196 std::cerr << "Missing value for argument." << std::endl;
00197 return false;
00198 }
00199 if (sscanf(argv[0], "%ud", &val) ==1){
00200 --argc;
00201 ++argv;
00202 return true;
00203 } else {
00204 std::cerr << "Unsigned integer not found at " << argv[0] << std::endl;
00205 return false;
00206 }
00207 }
00208 virtual void write_value(std::ostream &out) const {
00209 out << val;
00210 }
00211 virtual ~UIntTarget(){}
00212 };
00213
00214
00215 class Argument_helper::CharTarget: public Argument_target{
00216 public:
00217 char &val;
00218 CharTarget(char k, const char *lname,
00219 const char *arg_descr,
00220 const char *descr, char &b): Argument_target(k, std::string(lname),
00221 std::string(descr),
00222 std::string(arg_descr)), val(b){}
00223 CharTarget(const char *arg_descr,
00224 const char *descr, char &b): Argument_target(std::string(descr),
00225 std::string(arg_descr)), val(b){}
00226 virtual bool process(int &argc, const char **&argv){
00227 if (argc==0){
00228 std::cerr << "Missing value for argument." << std::endl;
00229 return false;
00230 }
00231 if (sscanf(argv[0], "%c", &val) ==1){
00232 --argc;
00233 ++argv;
00234 return true;
00235 } else {
00236 std::cerr << "Character not found at " << argv[0] << std::endl;
00237 return false;
00238 }
00239 }
00240 virtual void write_value(std::ostream &out) const {
00241 out << val;
00242 }
00243 virtual ~CharTarget(){}
00244 };
00245
00246
00247 class Argument_helper::StringTarget: public Argument_target{
00248 public:
00249 std::string &val;
00250 StringTarget(const char *arg_descr,
00251 const char *descr, std::string &b): Argument_target(0, std::string(),
00252 descr,
00253 arg_descr),
00254 val(b){}
00255
00256 StringTarget(char k, const char *lname, const char *arg_descr,
00257 const char *descr, std::string &b): Argument_target(k, lname, descr,
00258 arg_descr),
00259 val(b){}
00260
00261 virtual bool process(int &argc, const char **&argv){
00262 if (argc==0){
00263 std::cerr << "Missing string argument." << std::endl;
00264 return false;
00265 }
00266 val= argv[0];
00267 --argc;
00268 ++argv;
00269 return true;
00270 }
00271 virtual void write_value(std::ostream &out) const {
00272 out << val;
00273 }
00274 virtual ~StringTarget(){}
00275 };
00276
00277
00278 class Argument_helper::StringVectorTarget: public Argument_target{
00279 public:
00280 std::vector<std::string> &val;
00281
00282 StringVectorTarget(char k, const char *lname, const char *arg_descr,
00283 const char *descr, std::vector<std::string> &b): Argument_target(k, lname, descr,
00284 arg_descr),
00285 val(b){}
00286
00287 virtual bool process(int &argc, const char **&argv){
00288 while (argc >0 && argv[0][0] != '-'){
00289 val.push_back(argv[0]);
00290 --argc;
00291 ++argv;
00292 }
00293 return true;
00294 }
00295 virtual void write_value(std::ostream &out) const {
00296 for (unsigned int i=0; i< val.size(); ++i){
00297 out << val[i] << " ";
00298 }
00299 }
00300 virtual ~StringVectorTarget(){}
00301 };
00302
00303
00305
00306
00307 Argument_helper::Argument_helper(){
00308 author_="Someone";
00309 description_= "This program does something.";
00310 date_= "A long long time ago.";
00311 version_=-1;
00312 extra_arguments_=NULL;
00313 seen_end_named_=false;
00314 new_flag('v', "verbose", "Whether to print extra information", verbose);
00315 new_flag('V', "VERBOSE", "Whether to print lots of extra information", VERBOSE);
00316 }
00317
00318
00319
00320 void Argument_helper::set_string_vector(const char *arg_description,
00321 const char *description,
00322 std::vector<std::string> &dest){
00323 assert(extra_arguments_==NULL);
00324 extra_arguments_descr_= description;
00325 extra_arguments_arg_descr_= arg_description;
00326 extra_arguments_= &dest;
00327 }
00328
00329 void Argument_helper::set_author(const char *author){
00330 author_=author;
00331 }
00332
00333 void Argument_helper::set_description(const char *descr){
00334 description_= descr;
00335 }
00336
00337 void Argument_helper::set_name(const char *descr){
00338 name_= descr;
00339 }
00340
00341 void Argument_helper::set_version(float v){
00342 version_=v;
00343 }
00344
00345 void Argument_helper::set_version(const char *s){
00346 version_=atof(s);
00347 }
00348
00349 void Argument_helper::set_build_date(const char *date){
00350 date_=date;
00351 }
00352
00353 void Argument_helper::new_argument_target(Argument_target *t) {
00354 assert(t!= NULL);
00355 if (t->key != 0){
00356 if (short_names_.find(t->key) != short_names_.end()){
00357 std::cerr << "Two arguments are defined with the same character key, namely" << std::endl;
00358 short_names_[t->key]->write_usage(std::cerr);
00359 std::cerr << "\n and \n";
00360 t->write_usage(std::cerr);
00361 std::cerr << std::endl;
00362 }
00363 short_names_[t->key]= t;
00364 }
00365 if (!t->long_name.empty()){
00366 if (long_names_.find(t->long_name) != long_names_.end()){
00367 std::cerr << "Two arguments are defined with the same long key, namely" << std::endl;
00368 long_names_[t->long_name]->write_usage(std::cerr);
00369 std::cerr << "\n and \n";
00370 t->write_usage(std::cerr);
00371 std::cerr << std::endl;
00372 }
00373 long_names_[t->long_name]= t;
00374 }
00375 all_arguments_.push_back(t);
00376 }
00377
00378 void Argument_helper::new_flag(char key, const char *long_name, const char *description,bool &dest){
00379 Argument_target *t= new FlagTarget(key, long_name, description, dest);
00380 new_argument_target(t);
00381 };
00382
00383
00384
00385 void Argument_helper::new_string(const char *arg_description, const char *description,
00386 std::string &dest){
00387 Argument_target *t= new StringTarget(arg_description, description, dest);
00388 unnamed_arguments_.push_back(t);
00389 all_arguments_.push_back(t);
00390 };
00391 void Argument_helper::new_optional_string(const char *arg_description, const char *description,
00392 std::string &dest){
00393 Argument_target *t= new StringTarget(arg_description, description, dest);
00394 optional_unnamed_arguments_.push_back(t);
00395 };
00396 void Argument_helper::new_named_string(char key, const char *long_name,
00397 const char *arg_description, const char *description,
00398 std::string &dest){
00399 Argument_target *t= new StringTarget(key, long_name, arg_description, description, dest);
00400 new_argument_target(t);
00401 };
00402
00403
00404 void Argument_helper::new_named_string_vector(char key, const char *long_name,
00405 const char *arg_description, const char *description,
00406 std::vector<std::string> &dest){
00407 Argument_target *t= new StringVectorTarget(key, long_name, arg_description, description, dest);
00408 new_argument_target(t);
00409 };
00410
00411
00412
00413 void Argument_helper::new_int(const char *arg_description, const char *description,
00414 int &dest){
00415 Argument_target *t= new IntTarget(arg_description, description, dest);
00416 unnamed_arguments_.push_back(t);
00417 all_arguments_.push_back(t);
00418 };
00419 void Argument_helper::new_optional_int(const char *arg_description, const char *description,
00420 int &dest){
00421 Argument_target *t= new IntTarget(arg_description, description, dest);
00422 optional_unnamed_arguments_.push_back(t);
00423 };
00424 void Argument_helper::new_named_int(char key, const char *long_name,
00425 const char *arg_description, const char *description,
00426 int &dest){
00427 Argument_target *t= new IntTarget(key, long_name, arg_description, description, dest);
00428 new_argument_target(t);
00429 };
00430
00431 void Argument_helper::new_unsigned_int(const char *arg_description, const char *description,
00432 unsigned int &dest){
00433 Argument_target *t= new UIntTarget(arg_description, description, dest);
00434 unnamed_arguments_.push_back(t);
00435 all_arguments_.push_back(t);
00436 };
00437 void Argument_helper::new_optional_unsigned_int(const char *arg_description, const char *description,
00438 unsigned int &dest){
00439 Argument_target *t= new UIntTarget(arg_description, description, dest);
00440 optional_unnamed_arguments_.push_back(t);
00441 };
00442 void Argument_helper::new_named_unsigned_int(char key, const char *long_name,
00443 const char *arg_description, const char *description,
00444 unsigned int &dest){
00445 Argument_target *t= new UIntTarget(key, long_name, arg_description, description, dest);
00446 new_argument_target(t);
00447 };
00448
00449
00450 void Argument_helper::new_double(const char *arg_description, const char *description,
00451 double &dest){
00452 Argument_target *t= new DoubleTarget(arg_description, description, dest);
00453 unnamed_arguments_.push_back(t);
00454 all_arguments_.push_back(t);
00455 };
00456 void Argument_helper::new_optional_double(const char *arg_description, const char *description,
00457 double &dest){
00458 Argument_target *t= new DoubleTarget(arg_description, description, dest);
00459 optional_unnamed_arguments_.push_back(t);
00460 };
00461 void Argument_helper::new_named_double(char key, const char *long_name,
00462 const char *arg_description, const char *description,
00463 double &dest){
00464 Argument_target *t= new DoubleTarget(key, long_name, arg_description, description, dest);
00465 new_argument_target(t);
00466 };
00467
00468 void Argument_helper::new_char(const char *arg_description, const char *description,
00469 char &dest){
00470 Argument_target *t= new CharTarget(arg_description, description, dest);
00471 unnamed_arguments_.push_back(t);
00472 all_arguments_.push_back(t);
00473 };
00474 void Argument_helper::new_optional_char(const char *arg_description, const char *description,
00475 char &dest){
00476 Argument_target *t= new CharTarget(arg_description, description, dest);
00477 optional_unnamed_arguments_.push_back(t);
00478 };
00479 void Argument_helper::new_named_char(char key, const char *long_name,
00480 const char *arg_description, const char *description,
00481 char &dest){
00482 Argument_target *t= new CharTarget(key, long_name, arg_description, description, dest);
00483 new_argument_target(t);
00484 };
00485
00486
00487
00488 void Argument_helper::write_usage(std::ostream &out) const {
00489 out << name_ << " version " << version_ << ", by " << author_ << std::endl;
00490 out << description_ << std::endl;
00491 out << "Compiled on " << date_ << std::endl << std::endl;
00492 out << "Usage: " << name_ << " ";
00493 for (UVect::const_iterator it= unnamed_arguments_.begin(); it != unnamed_arguments_.end(); ++it){
00494 (*it)->write_name(out);
00495 out << " ";
00496 }
00497 for (UVect::const_iterator it= optional_unnamed_arguments_.begin();
00498 it != optional_unnamed_arguments_.end(); ++it){
00499 out << "[";
00500 (*it)->write_name(out);
00501 out << "] ";
00502 }
00503 if (extra_arguments_ != NULL) {
00504 out << "[" << extra_arguments_arg_descr_ << "]";
00505 }
00506
00507 out << std::endl << std::endl;
00508 out << "All arguments:\n";
00509 for (UVect::const_iterator it= unnamed_arguments_.begin(); it != unnamed_arguments_.end(); ++it){
00510 (*it)->write_usage(out);
00511 }
00512 for (UVect::const_iterator it= optional_unnamed_arguments_.begin();
00513 it != optional_unnamed_arguments_.end(); ++it){
00514 (*it)->write_usage(out);
00515 }
00516
00517 out << extra_arguments_arg_descr_ << ": " << extra_arguments_descr_ << std::endl;
00518 for (SMap::const_iterator it= short_names_.begin(); it != short_names_.end(); ++it){
00519 (it->second)->write_usage(out);
00520 }
00521 }
00522
00523
00524
00525 void Argument_helper::write_values(std::ostream &out) const {
00526 for (UVect::const_iterator it= unnamed_arguments_.begin(); it != unnamed_arguments_.end(); ++it){
00527 out << (*it)->description;
00528 out << ": ";
00529 (*it)->write_value(out);
00530 out << std::endl;
00531 }
00532 for (UVect::const_iterator it= optional_unnamed_arguments_.begin();
00533 it != optional_unnamed_arguments_.end(); ++it){
00534 out << (*it)->description;
00535 out << ": ";
00536 (*it)->write_value(out);
00537 out << std::endl;
00538 }
00539 if (extra_arguments_!=NULL){
00540 for (std::vector<std::string>::const_iterator it= extra_arguments_->begin();
00541 it != extra_arguments_->end(); ++it){
00542 out << *it << " ";
00543 }
00544 }
00545
00546 for (SMap::const_iterator it= short_names_.begin(); it != short_names_.end(); ++it){
00547 out << it->second->description;
00548 out << ": ";
00549 it->second->write_value(out);
00550 out << std::endl;
00551 }
00552 }
00553
00554 Argument_helper::~Argument_helper(){
00555 for (std::vector<Argument_target*>::iterator it= all_arguments_.begin();
00556 it != all_arguments_.end(); ++it){
00557 delete *it;
00558 }
00559 }
00560
00561
00562 void Argument_helper::process(int argc, const char **argv){
00563 name_= argv[0];
00564 ++argv;
00565 --argc;
00566
00567 current_unnamed_= unnamed_arguments_.begin();
00568 current_optional_unnamed_= optional_unnamed_arguments_.begin();
00569
00570 for ( int i=0; i< argc; ++i){
00571 if (strcmp(argv[i], "--help") == 0){
00572 write_usage(std::cout);
00573 exit(0);
00574 }
00575 }
00576
00577 while (argc != 0){
00578
00579 const char* cur_arg= argv[0];
00580 if (cur_arg[0]=='-' && !seen_end_named_){
00581 --argc; ++argv;
00582 if (cur_arg[1]=='-'){
00583 if (cur_arg[2] == '\0') {
00584
00585 seen_end_named_=true;
00586 } else {
00587
00588 LMap::iterator f= long_names_.find(cur_arg+2);
00589 if ( f != long_names_.end()){
00590 if (!f->second->process(argc, argv)) {
00591 handle_error();
00592 }
00593 } else {
00594 std::cerr<< "Invalid long argument "<< cur_arg << ".\n";
00595 handle_error();
00596 }
00597 }
00598 } else {
00599 if (cur_arg[1]=='\0') {
00600 std::cerr << "Invalid argument " << cur_arg << ".\n";
00601 handle_error();
00602 }
00603 SMap::iterator f= short_names_.find(cur_arg[1]);
00604 if ( f != short_names_.end()){
00605 if (!f->second->process(argc, argv)) {
00606 handle_error();
00607 }
00608 } else {
00609 std::cerr<< "Invalid short argument "<< cur_arg << ".\n";
00610 handle_error();
00611 }
00612 }
00613 } else {
00614 if (current_unnamed_ != unnamed_arguments_.end()){
00615 Argument_target *t= *current_unnamed_;
00616 t->process(argc, argv);
00617 ++current_unnamed_;
00618 } else if (current_optional_unnamed_ != optional_unnamed_arguments_.end()){
00619 Argument_target *t= *current_optional_unnamed_;
00620 t->process(argc, argv);
00621 ++current_optional_unnamed_;
00622 } else if (extra_arguments_!= NULL){
00623 extra_arguments_->push_back(cur_arg);
00624 --argc;
00625 ++argv;
00626 } else {
00627 std::cerr << "Invalid extra argument " << argv[0] << std::endl;
00628 handle_error();
00629 }
00630 }
00631 }
00632
00633 if (current_unnamed_ != unnamed_arguments_.end()){
00634 std::cerr << "Missing required arguments:" << std::endl;
00635 for (; current_unnamed_ != unnamed_arguments_.end(); ++current_unnamed_){
00636 (*current_unnamed_)->write_name(std::cerr);
00637 std::cerr << std::endl;
00638 }
00639 std::cerr << std::endl;
00640 handle_error();
00641 }
00642
00643 if (VERBOSE) verbose=true;
00644 }
00645
00646 void Argument_helper::handle_error() const {
00647 write_usage(std::cerr);
00648 exit(1);
00649 }
00650 }
00651