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