Main Page | Alphabetical List | Class List | File List | Class Members

Argument_helper.cc

00001 /*
00002  *
00003  * Argument Helper
00004  *
00005  * Daniel Russel drussel@alumni.princeton.edu
00006  * Stanford University
00007  *
00008  *
00009  * This software is not subject to copyright protection and is in the
00010  * public domain. Neither Stanford nor the author assume any
00011  * responsibility whatsoever for its use by other parties, and makes no
00012  * guarantees, expressed or implied, about its quality, reliability, or
00013  * any other characteristic.
00014  *
00015  */
00016 
00017 #include <utilities/Argument_helper.h>
00018 
00019 
00020 #include <iostream>
00021 #include <cstdlib>
00022 #include <cstdio>
00023 //#include <limits>
00024 #include <cassert>
00025 
00026 
00027 
00028 namespace dsr {
00029 
00030   bool verbose=false, VERBOSE=false;
00031 
00032 
00034 
00035   // This is a base class for representing one argument value.
00036   /* 
00037      This is inherited by many classes and which represent the different types. 
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             //std::cout << "Ending flags " << std::endl;
00585             seen_end_named_=true;
00586           } else {
00587             // long argument
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 

Generated on Thu Oct 21 17:29:54 2004 for Argument_helper by doxygen 1.3.6