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