github.com/platonnetwork/platon-go@v0.7.6/cases/tool/win/bls_win/include/cybozu/option.hpp (about)

     1  #pragma once
     2  /**
     3  	@file
     4  	@brief command line parser
     5  
     6  	@author MITSUNARI Shigeo(@herumi)
     7  */
     8  #include <string>
     9  #include <vector>
    10  #include <map>
    11  #include <sstream>
    12  #include <iostream>
    13  #include <limits>
    14  #include <stdio.h>
    15  #include <stdlib.h>
    16  #include <assert.h>
    17  #include <cybozu/exception.hpp>
    18  #include <cybozu/atoi.hpp>
    19  
    20  /*
    21  	Option parser
    22  
    23  	progName (opt1-name|opt2-name|...) param1 param2 ...
    24  	  param1:param1-help
    25  	  param2:param2-help
    26  	  -op1-name:opt1-help
    27  	  ...
    28  
    29  	How to setup
    30  	int num;
    31  	-n num ; (optional) option => appendOpt(&x, <defaultValue>, "num", "num-help");
    32  	-n num ; must option       => appendMust(&x, "num", "num-help");
    33  
    34  	std::vector<int> v;
    35  	-v s1 s2 s3 ...            => appendVec(&v, "v");
    36  
    37  	Remark1: terminate parsing of v if argv begins with '-[^0-9]'
    38  	Remark2: the begining character of opt-name is not a number ('0'...'9')
    39  	         because avoid conflict with minus number
    40  
    41  	std::string file1;
    42  	file1 is param             => appendParam(&file1, "input-file");
    43  	file2 is optional param    => appendParamOpt(&file2, "output-file");
    44  
    45  	How to use
    46  	opt.parse(argc, argv);
    47  
    48  	see sample/option_smpl.cpp
    49  */
    50  
    51  namespace cybozu {
    52  
    53  struct OptionError : public cybozu::Exception {
    54  	enum Type {
    55  		NoError = 0,
    56  		BAD_OPT = 1,
    57  		BAD_VALUE,
    58  		NO_VALUE,
    59  		OPT_IS_NECESSARY,
    60  		PARAM_IS_NECESSARY,
    61  		REDUNDANT_VAL,
    62  		BAD_ARGC
    63  	};
    64  	Type type;
    65  	int argPos;
    66  	OptionError()
    67  		: cybozu::Exception("OptionError", false)
    68  		, type(NoError)
    69  		, argPos(0)
    70  	{
    71  	}
    72  	cybozu::Exception& set(Type _type, int _argPos = 0)
    73  	{
    74  		this->type = _type;
    75  		this->argPos = _argPos;
    76  		switch (_type) {
    77  		case BAD_OPT:
    78  			(*this) << "bad opt";
    79  			break;
    80  		case BAD_VALUE:
    81  			(*this) << "bad value";
    82  			break;
    83  		case NO_VALUE:
    84  			(*this) << "no value";
    85  			break;
    86  		case OPT_IS_NECESSARY:
    87  			(*this) << "opt is necessary";
    88  			break;
    89  		case PARAM_IS_NECESSARY:
    90  			(*this) << "param is necessary";
    91  			break;
    92  		case REDUNDANT_VAL:
    93  			(*this) << "redundant argVal";
    94  			break;
    95  		case BAD_ARGC:
    96  			(*this) << "bad argc";
    97  		default:
    98  			break;
    99  		}
   100  		return *this;
   101  	}
   102  };
   103  
   104  namespace option_local {
   105  
   106  template<class T>
   107  bool convert(T* x, const char *str)
   108  {
   109  	std::istringstream is(str);
   110  	is >> *x;
   111  	return !!is;
   112  }
   113  
   114  template<>
   115  inline bool convert(std::string* x, const char *str)
   116  {
   117  	*x = str;
   118  	return true;
   119  }
   120  
   121  template<class T>
   122  bool convertInt(T* x, const char *str)
   123  {
   124  	if (str[0] == '0' && str[1] == 'x') {
   125  		bool b;
   126  		*x = cybozu::hextoi(&b, str + 2);
   127  		return b;
   128  	}
   129  	size_t len = strlen(str);
   130  	int factor = 1;
   131  	if (len > 1) {
   132  		switch (str[len - 1]) {
   133  		case 'k': factor = 1000; len--; break;
   134  		case 'm': factor = 1000 * 1000; len--; break;
   135  		case 'g': factor = 1000 * 1000 * 1000; len--; break;
   136  		case 'K': factor = 1024; len--; break;
   137  		case 'M': factor = 1024 * 1024; len--; break;
   138  		case 'G': factor = 1024 * 1024 * 1024; len--; break;
   139  		default: break;
   140  		}
   141  	}
   142  	bool b;
   143  	T y = cybozu::atoi(&b, str, len);
   144  	if (!b) return false;
   145  	if (factor > 1) {
   146  		if ((std::numeric_limits<T>::min)() / factor <= y
   147  			&& y <= (std::numeric_limits<T>::max)() / factor) {
   148  			*x = y * factor;
   149  		} else {
   150  			return false;
   151  		}
   152  	} else {
   153  		*x = y;
   154  	}
   155  	return true;
   156  }
   157  
   158  #define CYBOZU_OPTION_DEFINE_CONVERT_INT(type) \
   159  template<>inline bool convert(type* x, const char *str) { return convertInt(x, str); }
   160  
   161  CYBOZU_OPTION_DEFINE_CONVERT_INT(int)
   162  CYBOZU_OPTION_DEFINE_CONVERT_INT(long)
   163  CYBOZU_OPTION_DEFINE_CONVERT_INT(long long)
   164  
   165  CYBOZU_OPTION_DEFINE_CONVERT_INT(unsigned int)
   166  CYBOZU_OPTION_DEFINE_CONVERT_INT(unsigned long)
   167  CYBOZU_OPTION_DEFINE_CONVERT_INT(unsigned long long)
   168  
   169  #undef CYBOZU_OPTION_DEFINE_CONVERT_INT
   170  
   171  struct HolderBase {
   172  	virtual ~HolderBase(){}
   173  	virtual bool set(const char*) = 0;
   174  	virtual HolderBase *clone() const = 0;
   175  	virtual std::string toStr() const = 0;
   176  	virtual const void *get() const = 0;
   177  };
   178  
   179  template<class T>
   180  struct Holder : public HolderBase {
   181  	T *p_;
   182  	Holder(T *p) : p_(p) {}
   183  	HolderBase *clone() const { return new Holder(p_); }
   184  	bool set(const char *str) { return option_local::convert(p_, str); }
   185  	std::string toStr() const
   186  	{
   187  		std::ostringstream os;
   188  		os << *p_;
   189  		return os.str();
   190  	}
   191  	const void *get() const { return (void*)p_; }
   192  };
   193  
   194  /*
   195  	for gcc 7 with -fnew-ttp-matching
   196  	this specialization is not necessary under -fno-new-ttp-matching
   197  */
   198  template struct Holder<std::string>;
   199  
   200  template<class T, class Alloc, template<class T_, class Alloc_>class Container>
   201  struct Holder<Container<T, Alloc> > : public HolderBase {
   202  	typedef Container<T, Alloc> Vec;
   203  	Vec *p_;
   204  	Holder(Vec *p) : p_(p) {}
   205  	HolderBase *clone() const { return new Holder<Vec>(p_); }
   206  	bool set(const char *str)
   207  	{
   208  		T t;
   209  		bool b = option_local::convert(&t, str);
   210  		if (b) p_->push_back(t);
   211  		return b;
   212  	}
   213  	std::string toStr() const
   214  	{
   215  		std::ostringstream os;
   216  		bool isFirst = true;
   217  		for (typename Vec::const_iterator i = p_->begin(), ie = p_->end(); i != ie; ++i) {
   218  			if (isFirst) {
   219  				isFirst = false;
   220  			} else {
   221  				os << ' ';
   222  			}
   223  			os << *i;
   224  		}
   225  		return os.str();
   226  	}
   227  	const void *get() const { return (void*)p_; }
   228  };
   229  
   230  class Var {
   231  	HolderBase *p_;
   232  	bool isSet_;
   233  public:
   234  	Var() : p_(0), isSet_(false) { }
   235  	Var(const Var& rhs) : p_(rhs.p_->clone()), isSet_(false) { }
   236  	template<class T>
   237  	explicit Var(T *x) : p_(new Holder<T>(x)), isSet_(false) { }
   238  
   239  	~Var() { delete p_; }
   240  
   241  	void swap(Var& rhs) CYBOZU_NOEXCEPT
   242  	{
   243  		std::swap(p_, rhs.p_);
   244  		std::swap(isSet_, rhs.isSet_);
   245  	}
   246  	void operator=(const Var& rhs)
   247  	{
   248  		Var v(rhs);
   249  		swap(v);
   250  	}
   251  	bool set(const char *str)
   252  	{
   253  		isSet_ = true;
   254  		return p_->set(str);
   255  	}
   256  	std::string toStr() const { return p_ ? p_->toStr() : ""; }
   257  	bool isSet() const { return isSet_; }
   258  	const void *get() const { return p_ ? p_->get() : 0; }
   259  };
   260  
   261  } // option_local
   262  
   263  class Option {
   264  	enum Mode { // for opt
   265  		N_is0 = 0, // for bool by appendBoolOpt()
   266  		N_is1 = 1,
   267  		N_any = 2
   268  	};
   269  	enum ParamMode {
   270  		P_exact = 0, // one
   271  		P_optional = 1, // zero or one
   272  		P_variable = 2 // zero or greater
   273  	};
   274  	struct Info {
   275  		option_local::Var var;
   276  		Mode mode; // 0 or 1 or any ; for opt, not used for Param
   277  		bool isMust; // this option is must
   278  		std::string opt; // option param name without '-'
   279  		std::string help; // description of option
   280  
   281  		Info() : mode(N_is0), isMust(false) {}
   282  		template<class T>
   283  		Info(T* pvar, Mode mode, bool isMust, const char *opt, const std::string& help)
   284  			: var(pvar)
   285  			, mode(mode)
   286  			, isMust(isMust)
   287  			, opt(opt)
   288  			, help(help)
   289  		{
   290  		}
   291  		friend inline std::ostream& operator<<(std::ostream& os, const Info& self)
   292  		{
   293  			os << self.opt << '=' << self.var.toStr();
   294  			if (self.var.isSet()) {
   295  				os << " (set)";
   296  			} else {
   297  				os << " (default)";
   298  			}
   299  			return os;
   300  		}
   301  		void put() const
   302  		{
   303  			std::cout << *this;
   304  		}
   305  		void usage() const
   306  		{
   307  			printf("  -%s %s%s\n", opt.c_str(), help.c_str(), isMust ? " (must)" : "");
   308  		}
   309  		void shortUsage() const
   310  		{
   311  			printf(" -%s %s", opt.c_str(), mode == N_is0 ? "" : mode == N_is1 ? "para" : "para...");
   312  		}
   313  		bool isSet() const { return var.isSet(); }
   314  		const void *get() const { return var.get(); }
   315  	};
   316  	typedef std::vector<Info> InfoVec;
   317  	typedef std::vector<std::string> StrVec;
   318  	typedef std::map<std::string, size_t> OptMap;
   319  	InfoVec infoVec_;
   320  	InfoVec paramVec_;
   321  	Info remains_;
   322  	OptMap optMap_;
   323  	bool showOptUsage_;
   324  	ParamMode paramMode_;
   325  	std::string progName_;
   326  	std::string desc_;
   327  	std::string helpOpt_;
   328  	std::string help_;
   329  	std::string usage_;
   330  	StrVec delimiters_;
   331  	StrVec *remainsAfterDelimiter_;
   332  	int nextDelimiter_;
   333  	template<class T>
   334  	void appendSub(T *pvar, Mode mode, bool isMust, const char *opt, const std::string& help)
   335  	{
   336  		const char c = opt[0];
   337  		if ('0' <= c && c <= '9') throw cybozu::Exception("Option::appendSub:opt must begin with not number") << opt;
   338  		if (optMap_.find(opt) != optMap_.end()) {
   339  			throw cybozu::Exception("Option::append:duplicate option") << opt;
   340  		}
   341  		optMap_[opt] = infoVec_.size();
   342  		infoVec_.push_back(Info(pvar, mode, isMust, opt, help));
   343  	}
   344  
   345  	template<class T, class U>
   346  	void append(T *pvar, const U& defaultVal, bool isMust, const char *opt, const std::string& help = "")
   347  	{
   348  		*pvar = defaultVal;
   349  		appendSub(pvar, N_is1, isMust, opt, help);
   350  	}
   351  	/*
   352  		don't deal with negative number as option
   353  	*/
   354  	bool isOpt(const char *str) const
   355  	{
   356  		if (str[0] != '-') return false;
   357  		const char c = str[1];
   358  		if ('0' <= c && c <= '9') return false;
   359  		return true;
   360  	}
   361  	void verifyParamMode()
   362  	{
   363  		if (paramMode_ != P_exact) throw cybozu::Exception("Option:appendParamVec:appendParam is forbidden after appendParamOpt/appendParamVec");
   364  	}
   365  	std::string getBaseName(const std::string& name) const
   366  	{
   367  		size_t pos = name.find_last_of("/\\");
   368  		if (pos == std::string::npos) return name;
   369  		return name.substr(pos + 1);
   370  	}
   371  	bool inDelimiters(const std::string& str) const
   372  	{
   373  		return std::find(delimiters_.begin(), delimiters_.end(), str) != delimiters_.end();
   374  	}
   375  public:
   376  	Option()
   377  		: showOptUsage_(true)
   378  		, paramMode_(P_exact)
   379  		, remainsAfterDelimiter_(0)
   380  		, nextDelimiter_(-1)
   381  	{
   382  	}
   383  	virtual ~Option() {}
   384  	/*
   385  		append optional option with default value
   386  		@param pvar [in] pointer to option variable
   387  		@param defaultVal [in] default value
   388  		@param opt [in] option name
   389  		@param help [in] option help
   390  		@note you can use 123k, 56M if T is int/long/long long
   391  		k : *1000
   392  		m : *1000000
   393  		g : *1000000000
   394  		K : *1024
   395  		M : *1024*1024
   396  		G : *1024*1024*1024
   397  	*/
   398  	template<class T, class U>
   399  	void appendOpt(T *pvar, const U& defaultVal, const char *opt, const std::string& help = "")
   400  	{
   401  		append(pvar, defaultVal, false, opt, help);
   402  	}
   403  	/*
   404  		default value of *pvar is false
   405  	*/
   406  	void appendBoolOpt(bool *pvar, const char *opt, const std::string& help = "")
   407  	{
   408  		*pvar = false;
   409  		appendSub(pvar, N_is0, false, opt, help);
   410  	}
   411  	/*
   412  		append necessary option
   413  		@param pvar [in] pointer to option variable
   414  		@param opt [in] option name
   415  		@param help [in] option help
   416  	*/
   417  	template<class T>
   418  	void appendMust(T *pvar, const char *opt, const std::string& help = "")
   419  	{
   420  		append(pvar, T(), true, opt, help);
   421  	}
   422  	/*
   423  		append vector option
   424  		@param pvar [in] pointer to option variable
   425  		@param opt [in] option name
   426  		@param help [in] option help
   427  	*/
   428  	template<class T, class Alloc, template<class T_, class Alloc_>class Container>
   429  	void appendVec(Container<T, Alloc> *pvar, const char *opt, const std::string& help = "")
   430  	{
   431  		appendSub(pvar, N_any, false, opt, help);
   432  	}
   433  	/*
   434  		append parameter
   435  		@param pvar [in] pointer to parameter
   436  		@param opt [in] option name
   437  		@param help [in] option help
   438  	*/
   439  	template<class T>
   440  	void appendParam(T *pvar, const char *opt, const std::string& help = "")
   441  	{
   442  		verifyParamMode();
   443  		paramVec_.push_back(Info(pvar, N_is1, true, opt, help));
   444  	}
   445  	/*
   446  		append optional parameter
   447  		@param pvar [in] pointer to parameter
   448  		@param defaultVal [in] default value
   449  		@param opt [in] option name
   450  		@param help [in] option help
   451  		@note you can call appendParamOpt once after appendParam
   452  	*/
   453  	template<class T, class U>
   454  	void appendParamOpt(T *pvar, const U& defaultVal, const char *opt, const std::string& help = "")
   455  	{
   456  		verifyParamMode();
   457  		*pvar = defaultVal;
   458  		paramMode_ = P_optional;
   459  		paramVec_.push_back(Info(pvar, N_is1, false, opt, help));
   460  	}
   461  	/*
   462  		append remain parameter
   463  		@param pvar [in] pointer to vector of parameter
   464  		@param opt [in] option name
   465  		@param help [in] option help
   466  		@note you can call appendParamVec once after appendParam
   467  	*/
   468  	template<class T, class Alloc, template<class T_, class Alloc_>class Container>
   469  	void appendParamVec(Container<T, Alloc> *pvar, const char *name, const std::string& help = "")
   470  	{
   471  		verifyParamMode();
   472  		paramMode_ = P_variable;
   473  		remains_.var = option_local::Var(pvar);
   474  		remains_.mode = N_any;
   475  		remains_.isMust = false;
   476  		remains_.opt = name;
   477  		remains_.help = help;
   478  	}
   479  	void appendHelp(const char *opt, const std::string& help = ": show this message")
   480  	{
   481  		helpOpt_ = opt;
   482  		help_ = help;
   483  	}
   484  	/*
   485  		stop parsing after delimiter is found
   486  		@param delimiter [in] string to stop
   487  		@param remain [out] set remaining strings if remain
   488  	*/
   489  	void setDelimiter(const std::string& delimiter, std::vector<std::string> *remain = 0)
   490  	{
   491  		delimiters_.push_back(delimiter);
   492  		remainsAfterDelimiter_ = remain;
   493  	}
   494  	/*
   495  		stop parsing after delimiter is found
   496  		@param delimiter [in] string to stop to append list of delimiters
   497  	*/
   498  	void appendDelimiter(const std::string& delimiter)
   499  	{
   500  		delimiters_.push_back(delimiter);
   501  	}
   502  	/*
   503  		clear list of delimiters
   504  	*/
   505  	void clearDelimiterList() { delimiters_.clear(); }
   506  	/*
   507  		return the next position of delimiter between [0, argc]
   508  		@note return argc if delimiter is not set nor found
   509  	*/
   510  	int getNextPositionOfDelimiter() const { return nextDelimiter_; }
   511  	/*
   512  		parse (argc, argv)
   513  		@param argc [in] argc of main
   514  		@param argv [in] argv of main
   515  		@param startPos [in] start position of argc
   516  		@param progName [in] used instead of argv[0]
   517  	*/
   518  	bool parse(int argc, const char *const argv[], int startPos = 1, const char *progName = 0)
   519  	{
   520  		if (argc < 1 || startPos > argc) return false;
   521  		progName_ = getBaseName(progName ? progName : argv[startPos - 1]);
   522  		nextDelimiter_ = argc;
   523  		OptionError err;
   524  		for (int pos = startPos; pos < argc; pos++) {
   525  			if (inDelimiters(argv[pos])) {
   526  				nextDelimiter_ = pos + 1;
   527  				if (remainsAfterDelimiter_) {
   528  					for (int i = nextDelimiter_; i < argc; i++) {
   529  						remainsAfterDelimiter_->push_back(argv[i]);
   530  					}
   531  				}
   532                  break;
   533  			}
   534  			if (isOpt(argv[pos])) {
   535  				const std::string str = argv[pos] + 1;
   536  				if (helpOpt_ == str) {
   537  					usage();
   538  					exit(0);
   539  				}
   540  				OptMap::const_iterator i = optMap_.find(str);
   541  				if (i == optMap_.end()) {
   542  					err.set(OptionError::BAD_OPT, pos);
   543  					goto ERR;
   544  				}
   545  
   546  				Info& info = infoVec_[i->second];
   547  				switch (info.mode) {
   548  				case N_is0:
   549  					if (!info.var.set("1")) {
   550  						err.set(OptionError::BAD_VALUE, pos);
   551  						goto ERR;
   552  					}
   553  					break;
   554  				case N_is1:
   555  					pos++;
   556  					if (pos == argc) {
   557  						err.set(OptionError::BAD_VALUE, pos) << (std::string("no value for -") + info.opt);
   558  						goto ERR;
   559  					}
   560  					if (!info.var.set(argv[pos])) {
   561  						err.set(OptionError::BAD_VALUE, pos) << (std::string(argv[pos]) + " for -" + info.opt);
   562  						goto ERR;
   563  					}
   564  					break;
   565  				case N_any:
   566  				default:
   567  					{
   568  						pos++;
   569  						int j = 0;
   570  						while (pos < argc && !isOpt(argv[pos])) {
   571  							if (!info.var.set(argv[pos])) {
   572  								err.set(OptionError::BAD_VALUE, pos) << (std::string(argv[pos]) + " for -" + info.opt) << j;
   573  								goto ERR;
   574  							}
   575  							pos++;
   576  							j++;
   577  						}
   578  						if (j > 0) {
   579  							pos--;
   580  						} else {
   581  							err.set(OptionError::NO_VALUE, pos) << (std::string("for -") + info.opt);
   582  							goto ERR;
   583  						}
   584  					}
   585  					break;
   586  				}
   587  			} else {
   588  				bool used = false;
   589  				for (size_t i = 0; i < paramVec_.size(); i++) {
   590  					Info& param = paramVec_[i];
   591  					if (!param.var.isSet()) {
   592  						if (!param.var.set(argv[pos])) {
   593  							err.set(OptionError::BAD_VALUE, pos) << (std::string(argv[pos]) + " for " + param.opt);
   594  							goto ERR;
   595  						}
   596  						used = true;
   597  						break;
   598  					}
   599  				}
   600  				if (!used) {
   601  					if (paramMode_ == P_variable) {
   602  						remains_.var.set(argv[pos]);
   603  					} else {
   604  						err.set(OptionError::REDUNDANT_VAL, pos) << argv[pos];
   605  						goto ERR;
   606  					}
   607  				}
   608  			}
   609  		}
   610  		// check whether must-opt is set
   611  		for (size_t i = 0; i < infoVec_.size(); i++) {
   612  			const Info& info = infoVec_[i];
   613  			if (info.isMust && !info.var.isSet()) {
   614  				err.set(OptionError::OPT_IS_NECESSARY) << info.opt;
   615  				goto ERR;
   616  			}
   617  		}
   618  		// check whether param is set
   619  		for (size_t i = 0; i < paramVec_.size(); i++) {
   620  			const Info& param = paramVec_[i];
   621  			if (param.isMust && !param.var.isSet()) {
   622  				err.set(OptionError::PARAM_IS_NECESSARY) << param.opt;
   623  				goto ERR;
   624  			}
   625  		}
   626  		// check whether remains is set
   627  		if (paramMode_ == P_variable && remains_.isMust && !remains_.var.isSet()) {
   628  			err.set(OptionError::PARAM_IS_NECESSARY) << remains_.opt;
   629  			goto ERR;
   630  		}
   631  		return true;
   632  	ERR:
   633  		assert(err.type);
   634  		printf("%s\n", err.what());
   635  		return false;
   636  	}
   637  	/*
   638  		show desc at first in usage()
   639  	*/
   640  	void setDescription(const std::string& desc)
   641  	{
   642  		desc_ = desc;
   643  	}
   644  	/*
   645  		show command line after desc
   646  		don't put option message if not showOptUsage
   647  	*/
   648  	void setUsage(const std::string& usage, bool showOptUsage = false)
   649  	{
   650  		usage_ = usage;
   651  		showOptUsage_ = showOptUsage;
   652  	}
   653  	void usage() const
   654  	{
   655  		if (!desc_.empty()) printf("%s\n", desc_.c_str());
   656  		if (usage_.empty()) {
   657  			printf("usage:%s", progName_.c_str());
   658  			if (!infoVec_.empty()) printf(" [opt]");
   659  			for (size_t i = 0; i < infoVec_.size(); i++) {
   660  				if (infoVec_[i].isMust) infoVec_[i].shortUsage();
   661  			}
   662  			for (size_t i = 0; i < paramVec_.size(); i++) {
   663  				printf(" %s", paramVec_[i].opt.c_str());
   664  			}
   665  			if (paramMode_ == P_variable) {
   666  				printf(" %s", remains_.opt.c_str());
   667  			}
   668  			printf("\n");
   669  		} else {
   670  			printf("%s\n", usage_.c_str());
   671  			if (!showOptUsage_) return;
   672  		}
   673  		for (size_t i = 0; i < paramVec_.size(); i++) {
   674  			const Info& param = paramVec_[i];
   675  			if (!param.help.empty()) printf("  %s %s\n", paramVec_[i].opt.c_str(), paramVec_[i].help.c_str());
   676  		}
   677  		if (!remains_.help.empty()) printf("  %s %s\n", remains_.opt.c_str(), remains_.help.c_str());
   678  		if (!helpOpt_.empty()) {
   679  			printf("  -%s %s\n", helpOpt_.c_str(), help_.c_str());
   680  		}
   681  		for (size_t i = 0; i < infoVec_.size(); i++) {
   682  			infoVec_[i].usage();
   683  		}
   684  	}
   685  	friend inline std::ostream& operator<<(std::ostream& os, const Option& self)
   686  	{
   687  		for (size_t i = 0; i < self.paramVec_.size(); i++) {
   688  			const Info& param = self.paramVec_[i];
   689  			os << param.opt << '=' << param.var.toStr() << std::endl;
   690  		}
   691  		if (self.paramMode_ == P_variable) {
   692  			os << "remains=" << self.remains_.var.toStr() << std::endl;
   693  		}
   694  		for (size_t i = 0; i < self.infoVec_.size(); i++) {
   695  			os << self.infoVec_[i] << std::endl;
   696  		}
   697  		return os;
   698  	}
   699  	void put() const
   700  	{
   701  		std::cout << *this;
   702  	}
   703  	/*
   704  		whether pvar is set or not
   705  	*/
   706  	template<class T>
   707  	bool isSet(const T* pvar) const
   708  	{
   709  		const void *p = static_cast<const void*>(pvar);
   710  		for (size_t i = 0; i < paramVec_.size(); i++) {
   711  			const Info& v = paramVec_[i];
   712  			if (v.get() == p) return v.isSet();
   713  		}
   714  		if (remains_.get() == p) return remains_.isSet();
   715  		for (size_t i = 0; i < infoVec_.size(); i++) {
   716  			const Info& v = infoVec_[i];
   717  			if (v.get() == p) return v.isSet();
   718  		}
   719  		throw cybozu::Exception("Option:isSet:no assigned var") << pvar;
   720  	}
   721  };
   722  
   723  } // cybozu