00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifndef ARGSTREAM_H
00019 #define ARGSTREAM_H
00020
00021 #include <string>
00022 #include <list>
00023 #include <deque>
00024 #include <map>
00025 #include <vector>
00026 #include <stdexcept>
00027 #include <sstream>
00028 #include <iostream>
00029
00030 namespace
00031 {
00032 class argstream;
00033
00034
00035
00036
00037 template<class T>
00038 class ValueHolder;
00039
00040 template <class T>
00041 argstream& operator>> (argstream&, const ValueHolder<T>&);
00042
00043 template<class T>
00044 class ValueHolder
00045 {
00046 public:
00047 ValueHolder(char s,
00048 const char* l,
00049 T& b,
00050 const char* desc,
00051 bool mandatory);
00052 ValueHolder(const char* l,
00053 T& b,
00054 const char* desc,
00055 bool mandatory);
00056 ValueHolder(char s,
00057 T& b,
00058 const char* desc,
00059 bool mandatory);
00060 friend argstream& operator>><>(argstream& s,const ValueHolder<T>& v);
00061 std::string name() const;
00062 std::string description() const;
00063 private:
00064 std::string shortName_;
00065 std::string longName_;
00066 T* value_;
00067 T initialValue_;
00068 std::string description_;
00069 bool mandatory_;
00070 };
00071 template <class T>
00072 inline ValueHolder<T>
00073 parameter(char s,
00074 const char* l,
00075 T& b,
00076 const char* desc="",
00077 bool mandatory = true)
00078 {
00079 return ValueHolder<T>(s,l,b,desc,mandatory);
00080 }
00081 template <class T>
00082 inline ValueHolder<T>
00083 parameter(char s,
00084 T& b,
00085 const char* desc="",
00086 bool mandatory = true)
00087 {
00088 return ValueHolder<T>(s,b,desc,mandatory);
00089 }
00090 template <class T>
00091 inline ValueHolder<T>
00092 parameter(const char* l,
00093 T& b,
00094 const char* desc="",
00095 bool mandatory = true)
00096 {
00097 return ValueHolder<T>(l,b,desc,mandatory);
00098 }
00099
00100
00101
00102 class OptionHolder
00103 {
00104 public:
00105 inline OptionHolder(char s,
00106 const char* l,
00107 bool& b,
00108 const char* desc);
00109 inline OptionHolder(const char* l,
00110 bool& b,
00111 const char* desc);
00112 inline OptionHolder(char s,
00113 bool& b,
00114 const char* desc);
00115 friend argstream& operator>>(argstream& s,const OptionHolder& v);
00116 inline std::string name() const;
00117 inline std::string description() const;
00118 protected:
00119 inline OptionHolder(char s,
00120 const char* l,
00121 const char* desc);
00122 friend OptionHolder help(char s='h',
00123 const char* l="help",
00124 const char* desc="Display this help");
00125 private:
00126 std::string shortName_;
00127 std::string longName_;
00128 bool* value_;
00129 std::string description_;
00130 };
00131 inline OptionHolder
00132 option(char s,
00133 const char* l,
00134 bool& b,
00135 const char* desc="")
00136 {
00137 return OptionHolder(s,l,b,desc);
00138 }
00139 inline OptionHolder
00140 option(char s,
00141 bool& b,
00142 const char* desc="")
00143 {
00144 return OptionHolder(s,b,desc);
00145 }
00146 inline OptionHolder
00147 option(const char* l,
00148 bool& b,
00149 const char* desc="")
00150 {
00151 return OptionHolder(l,b,desc);
00152 }
00153 inline OptionHolder
00154 help(char s,
00155 const char* l,
00156 const char* desc)
00157 {
00158 return OptionHolder(s,l,desc);
00159 }
00160
00161
00162
00163 template<class T,class O>
00164 class ValuesHolder;
00165
00166 template <class T,class O>
00167 argstream& operator>>(argstream&, const ValuesHolder<T,O>&);
00168
00169 template<class T,class O>
00170 class ValuesHolder
00171 {
00172 public:
00173 ValuesHolder(const O& o,
00174 const char* desc,
00175 int len);
00176 friend argstream& operator>><>(argstream& s,const ValuesHolder<T,O>& v);
00177 std::string name() const;
00178 std::string description() const;
00179 typedef T value_type;
00180 private:
00181 mutable O value_;
00182 std::string description_;
00183 int len_;
00184 char letter_;
00185 };
00186 template<class T,class O>
00187 inline ValuesHolder<T,O>
00188 values(const O& o,
00189 const char* desc="",
00190 int len=-1)
00191 {
00192 return ValuesHolder<T,O>(o,desc,len);
00193 }
00194
00195
00196
00197 template <class T>
00198 class ValueParser
00199 {
00200 public:
00201 inline T operator()(const std::string& s) const
00202 {
00203 std::istringstream is(s);
00204 T t;
00205 is>>t;
00206 return t;
00207 }
00208 };
00209
00210
00211
00212 template <>
00213 class ValueParser<std::string>
00214 {
00215 public:
00216 inline std::string operator()(const std::string& s) const
00217 {
00218 return s;
00219 }
00220 };
00221
00222
00223
00224 class argstream
00225 {
00226 public:
00227 inline argstream(int argc,char** argv);
00228 inline argstream(const char* c);
00229 template<class T>
00230 friend argstream& operator>>(argstream& s,const ValueHolder<T>& v);
00231 friend inline argstream& operator>>(argstream& s,const OptionHolder& v);
00232 template<class T,class O>
00233 friend argstream& operator>>(argstream& s,const ValuesHolder<T,O>& v);
00234
00235 inline bool helpRequested() const;
00236 inline bool isOk() const;
00237 inline std::string errorLog() const;
00238 inline std::string usage() const;
00239 inline void defaultErrorHandling(bool ignoreUnused=false) const;
00240 static inline char uniqueLetter();
00241 protected:
00242 void parse(int argc,char** argv);
00243 private:
00244 typedef std::list<std::string>::iterator value_iterator;
00245 typedef std::pair<std::string,std::string> help_entry;
00246 std::string progName_;
00247 std::map<std::string,value_iterator> options_;
00248 std::list<std::string> values_;
00249 bool minusActive_;
00250 bool isOk_;
00251 std::deque<help_entry> argHelps_;
00252 std::string cmdLine_;
00253 std::deque<std::string> errors_;
00254 bool helpRequested_;
00255 };
00256
00257
00258
00259 template<class T>
00260 ValueHolder<T>::ValueHolder(char s,
00261 const char* l,
00262 T& v,
00263 const char* desc,
00264 bool mandatory)
00265 : shortName_(1,s),
00266 longName_(l),
00267 value_(&v),
00268 initialValue_(v),
00269 description_(desc),
00270 mandatory_(mandatory)
00271 {
00272 }
00273 template<class T>
00274 ValueHolder<T>::ValueHolder(const char* l,
00275 T& v,
00276 const char* desc,
00277 bool mandatory)
00278 : longName_(l),
00279 value_(&v),
00280 initialValue_(v),
00281 description_(desc),
00282 mandatory_(mandatory)
00283 {
00284 }
00285 template<class T>
00286 ValueHolder<T>::ValueHolder(char s,
00287 T& v,
00288 const char* desc,
00289 bool mandatory)
00290 : shortName_(1,s),
00291 value_(&v),
00292 initialValue_(v),
00293 description_(desc),
00294 mandatory_(mandatory)
00295 {
00296 }
00297 template<class T>
00298 std::string
00299 ValueHolder<T>::name() const
00300 {
00301 std::ostringstream os;
00302 if (!shortName_.empty()) os<<'-'<<shortName_;
00303 if (!longName_.empty()) {
00304 if (!shortName_.empty()) os<<'/';
00305 os<<"--"<<longName_;
00306 }
00307 return os.str();
00308 }
00309 template<class T>
00310 std::string
00311 ValueHolder<T>::description() const
00312 {
00313 std::ostringstream os;
00314 os<<description_;
00315 if (mandatory_)
00316 {
00317 os<<"(mandatory)";
00318 }
00319 else
00320 {
00321 os<<"(default="<<initialValue_<<")";
00322 }
00323 return os.str();
00324 }
00325
00326
00327
00328 inline OptionHolder::OptionHolder(char s,
00329 const char* l,
00330 bool& b,
00331 const char* desc)
00332 : shortName_(1,s),
00333 longName_(l),
00334 value_(&b),
00335 description_(desc)
00336 {
00337 }
00338 inline OptionHolder::OptionHolder(const char* l,
00339 bool& b,
00340 const char* desc)
00341 : longName_(l),
00342 value_(&b),
00343 description_(desc)
00344 {
00345 }
00346 inline OptionHolder::OptionHolder(char s,
00347 bool& b,
00348 const char* desc)
00349 : shortName_(1,s),
00350 value_(&b),
00351 description_(desc)
00352 {
00353 }
00354 inline OptionHolder::OptionHolder(char s,
00355 const char* l,
00356 const char* desc)
00357 : shortName_(1,s),
00358 longName_(l),
00359 value_(NULL),
00360 description_(desc)
00361 {
00362 }
00363 inline std::string
00364 OptionHolder::name() const
00365 {
00366 std::ostringstream os;
00367 if (!shortName_.empty()) os<<'-'<<shortName_;
00368 if (!longName_.empty())
00369 {
00370 if (!shortName_.empty()) os<<'/';
00371 os<<"--"<<longName_;
00372 }
00373 return os.str();
00374 }
00375 inline std::string
00376 OptionHolder::description() const
00377 {
00378 return description_;
00379 }
00380
00381
00382
00383 template<class T,class O>
00384 ValuesHolder<T,O>::ValuesHolder(const O& o,
00385 const char* desc,
00386 int len)
00387 : value_(o),
00388 description_(desc),
00389 len_(len)
00390 {
00391 letter_ = argstream::uniqueLetter();
00392 }
00393 template <class T,class O>
00394 std::string
00395 ValuesHolder<T,O>::name() const
00396 {
00397 std::ostringstream os;
00398 os<<letter_<<"i";
00399 return os.str();
00400 }
00401 template <class T,class O>
00402 std::string
00403 ValuesHolder<T,O>::description() const
00404 {
00405 return description_;
00406 }
00407
00408
00409
00410 inline
00411 argstream::argstream(int argc,char** argv)
00412 : progName_(argv[0]),
00413 minusActive_(true),
00414 isOk_(true)
00415 {
00416 parse(argc,argv);
00417 }
00418 inline
00419 argstream::argstream(const char* c)
00420 : progName_(""),
00421 minusActive_(true),
00422 isOk_(true)
00423 {
00424 std::string s(c);
00425
00426
00427 std::deque<std::string> args;
00428 args.push_back("");
00429 std::istringstream is(s);
00430 while (is.good())
00431 {
00432 std::string t;
00433 is>>t;
00434 args.push_back(t);
00435 }
00436 std::vector<char*> pargs(args.size());
00437 std::vector<char*>::iterator p = pargs.begin();
00438 for (std::deque<std::string>::const_iterator
00439 iter = args.begin();
00440 iter != args.end();++iter)
00441 {
00442 *p++ = const_cast<char*>(iter->c_str());
00443 }
00444 parse(args.size(),&(pargs[0]));
00445 }
00446 inline void
00447 argstream::parse(int argc,char** argv)
00448 {
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 value_iterator* lastOption = NULL;
00468 for (char** a = argv,**astop=a+argc;++a!=astop;)
00469 {
00470 std::string s(*a);
00471 if (minusActive_ && s[0] == '-')
00472 {
00473 if (s.size() > 1 && s[1] == '-')
00474 {
00475 if (s.size() == 2)
00476 {
00477 minusActive_ = false;
00478 continue;
00479 }
00480 lastOption = &(options_[s.substr(2)] = values_.end());
00481 }
00482 else
00483 {
00484 if (s.size() > 1)
00485 {
00486
00487 for (std::string::const_iterator cter = s.begin();
00488 ++cter != s.end();)
00489 {
00490 if (*cter == '-')
00491 {
00492 isOk_ = false;
00493 std::ostringstream os;
00494 os<<"- in the middle of a switch "<<a;
00495 errors_.push_back(os.str());
00496 break;
00497 }
00498 lastOption = &(options_[std::string(1,*cter)] = values_.end());
00499 }
00500 }
00501 else
00502 {
00503 isOk_ = false;
00504 errors_.push_back("Invalid argument -");
00505 break;
00506 }
00507 }
00508 }
00509 else
00510 {
00511 values_.push_back(s);
00512 if (lastOption != NULL)
00513 {
00514 *lastOption = --values_.end();
00515 }
00516 lastOption = NULL;
00517 }
00518 }
00519 #ifdef ARGSTREAM_DEBUG
00520 for (std::map<std::string,value_iterator>::const_iterator
00521 iter = options_.begin();iter != options_.end();++iter)
00522 {
00523 std::cout<<"DEBUG: option "<<iter->first;
00524 if (iter->second != values_.end())
00525 {
00526 std::cout<<" -> "<<*(iter->second);
00527 }
00528 std::cout<<std::endl;
00529 }
00530 for (std::list<std::string>::const_iterator
00531 iter = values_.begin();iter != values_.end();++iter)
00532 {
00533 std::cout<<"DEBUG: value "<<*iter<<std::endl;
00534 }
00535 #endif // ARGSTREAM_DEBUG
00536 }
00537 inline bool
00538 argstream::isOk() const
00539 {
00540 return isOk_;
00541 }
00542 inline bool
00543 argstream::helpRequested() const
00544 {
00545 return helpRequested_;
00546 }
00547 inline std::string
00548 argstream::usage() const
00549 {
00550 std::ostringstream os;
00551 os<<"usage: "<<progName_<<cmdLine_<<'\n';
00552 unsigned int lmax = 0;
00553 for (std::deque<help_entry>::const_iterator
00554 iter = argHelps_.begin();iter != argHelps_.end();++iter)
00555 {
00556 if (lmax<iter->first.size()) lmax = iter->first.size();
00557 }
00558 for (std::deque<help_entry>::const_iterator
00559 iter = argHelps_.begin();iter != argHelps_.end();++iter)
00560 {
00561 os<<'\t'<<iter->first<<std::string(lmax-iter->first.size(),' ')
00562 <<" : "<<iter->second<<'\n';
00563 }
00564 return os.str();
00565 }
00566 inline std::string
00567 argstream::errorLog() const
00568 {
00569 std::string s;
00570 for(std::deque<std::string>::const_iterator iter = errors_.begin();
00571 iter != errors_.end();++iter)
00572 {
00573 s += *iter;
00574 s += '\n';
00575 }
00576 return s;
00577 }
00578 inline char
00579 argstream::uniqueLetter()
00580 {
00581 static unsigned int c = 'a';
00582 return c++;
00583 }
00584 template<class T>
00585 argstream&
00586 operator>>(argstream& s,const ValueHolder<T>& v)
00587 {
00588
00589
00590
00591 #ifdef ARGSTREAM_DEBUG
00592 std::cout<<"DEBUG: searching "<<v.shortName_<<" "<<v.longName_<<std::endl;
00593 #endif
00594 s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
00595 if (v.mandatory_)
00596 {
00597 if (!v.shortName_.empty())
00598 {
00599 s.cmdLine_ += " -";
00600 s.cmdLine_ += v.shortName_;
00601 }
00602 else
00603 {
00604 s.cmdLine_ += " --";
00605 s.cmdLine_ += v.longName_;
00606 }
00607 s.cmdLine_ += " value";
00608 }
00609 else
00610 {
00611 if (!v.shortName_.empty())
00612 {
00613 s.cmdLine_ += " [-";
00614 s.cmdLine_ += v.shortName_;
00615 }
00616 else
00617 {
00618 s.cmdLine_ += " [--";
00619 s.cmdLine_ += v.longName_;
00620 }
00621 s.cmdLine_ += " value]";
00622
00623 }
00624 std::map<std::string,argstream::value_iterator>::iterator iter =
00625 s.options_.find(v.shortName_);
00626 if (iter == s.options_.end())
00627 {
00628 iter = s.options_.find(v.longName_);
00629 }
00630 if (iter != s.options_.end())
00631 {
00632
00633
00634
00635 if (iter->second != s.values_.end())
00636 {
00637 #ifdef ARGSTREAM_DEBUG
00638 std::cout<<"DEBUG: found value "<<*(iter->second)<<std::endl;
00639 #endif
00640 ValueParser<T> p;
00641 *(v.value_) = p(*(iter->second));
00642
00643
00644
00645 s.values_.erase(iter->second);
00646 for (std::map<std::string,argstream::value_iterator>::iterator
00647 jter = s.options_.begin();jter != s.options_.end();++jter)
00648 {
00649 if (jter->second == iter->second)
00650 {
00651 jter->second = s.values_.end();
00652 }
00653 }
00654 s.options_.erase(iter);
00655 }
00656 else
00657 {
00658 s.isOk_ = false;
00659 std::ostringstream os;
00660 os<<"No value following switch "<<iter->first
00661 <<" on command line";
00662 s.errors_.push_back(os.str());
00663 }
00664 }
00665 else
00666 {
00667 if (v.mandatory_)
00668 {
00669 s.isOk_ = false;
00670 std::ostringstream os;
00671 os<<"Mandatory parameter ";
00672 if (!v.shortName_.empty()) os<<'-'<<v.shortName_;
00673 if (!v.longName_.empty())
00674 {
00675 if (!v.shortName_.empty()) os<<'/';
00676 os<<"--"<<v.longName_;
00677 }
00678 os<<" missing";
00679 s.errors_.push_back(os.str());
00680 }
00681 }
00682 return s;
00683 }
00684 inline argstream&
00685 operator>>(argstream& s,const OptionHolder& v)
00686 {
00687
00688
00689
00690 #ifdef ARGSTREAM_DEBUG
00691 std::cout<<"DEBUG: searching "<<v.shortName_<<" "<<v.longName_<<std::endl;
00692 #endif
00693 s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
00694 {
00695 std::string c;
00696 if (!v.shortName_.empty())
00697 {
00698 c += " [-";
00699 c += v.shortName_;
00700 }
00701 else
00702 {
00703 c += " [--";
00704 c += v.longName_;
00705 }
00706 c += "]";
00707 s.cmdLine_ = c+s.cmdLine_;
00708 }
00709 std::map<std::string,argstream::value_iterator>::iterator iter =
00710 s.options_.find(v.shortName_);
00711 if (iter == s.options_.end())
00712 {
00713 iter = s.options_.find(v.longName_);
00714 }
00715 if (iter != s.options_.end())
00716 {
00717
00718
00719 if (v.value_ != NULL)
00720 {
00721 *(v.value_) = true;
00722 }
00723 else
00724 {
00725 s.helpRequested_ = true;
00726 }
00727
00728 s.options_.erase(iter);
00729 }
00730 else
00731 {
00732 if (v.value_ != NULL)
00733 {
00734 *(v.value_) = false;
00735 }
00736 else
00737 {
00738 s.helpRequested_ = false;
00739 }
00740 }
00741 return s;
00742 }
00743 template<class T,class O>
00744 argstream&
00745 operator>>(argstream& s,const ValuesHolder<T,O>& v)
00746 {
00747 s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
00748 {
00749 std::ostringstream os;
00750 os<<' '<<v.letter_<<'1';
00751 switch (v.len_)
00752 {
00753 case -1:
00754 os<<"...";
00755 break;
00756 case 1:
00757 break;
00758 default:
00759 os<<"..."<<v.letter_<<v.len_;
00760 break;
00761 }
00762 s.cmdLine_ += os.str();
00763 }
00764 std::list<std::string>::iterator first = s.values_.begin();
00765
00766
00767 int n = v.len_ != -1?v.len_:s.values_.size();
00768 while (first != s.values_.end() && n-->0)
00769 {
00770
00771 ValueParser<T> p;
00772 *(v.value_++) = p(*first );
00773 s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
00774
00775
00776 for (std::map<std::string,argstream::value_iterator>::iterator
00777 jter = s.options_.begin();jter != s.options_.end();++jter)
00778 {
00779 if (jter->second == first)
00780 {
00781 jter->second = s.values_.end();
00782 }
00783 }
00784 ++first;
00785 }
00786
00787 if (n != 0)
00788 {
00789 s.isOk_ = false;
00790 std::ostringstream os;
00791 os<<"Expecting "<<v.len_<<" values";
00792 s.errors_.push_back(os.str());
00793 }
00794
00795 s.values_.erase(s.values_.begin(),first);
00796 return s;
00797 }
00798 inline void
00799 argstream::defaultErrorHandling(bool ignoreUnused) const
00800 {
00801 if (helpRequested_)
00802 {
00803 std::cout<<usage();
00804 exit(1);
00805 }
00806 if (!isOk_)
00807 {
00808 std::cerr<<errorLog();
00809 exit(1);
00810 }
00811 if (!ignoreUnused &&
00812 (!values_.empty() || !options_.empty()))
00813 {
00814 std::cerr<<"Unused arguments"<<std::endl;
00815 exit(1);
00816 }
00817 }
00818 };
00819 #endif // ARGSTREAM_H
00820
00821
00822
00823
00824
00825