820 lines
25 KiB
C
820 lines
25 KiB
C
|
/* Copyright (C) 2004 Xavier Decoret <Xavier.Decoret@imag.fr>
|
||
|
*
|
||
|
* argsteam is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* Foobar is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with Foobar; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*/
|
||
|
|
||
|
#ifndef ARGSTREAM_H
|
||
|
#define ARGSTREAM_H
|
||
|
|
||
|
|
||
|
#include <string>
|
||
|
#include <list>
|
||
|
#include <deque>
|
||
|
#include <map>
|
||
|
#include <stdexcept>
|
||
|
#include <sstream>
|
||
|
#include <iostream>
|
||
|
|
||
|
namespace
|
||
|
{
|
||
|
class argstream;
|
||
|
|
||
|
template<class T>
|
||
|
class ValueHolder;
|
||
|
|
||
|
template <typename T>
|
||
|
argstream& operator>> (argstream&, const ValueHolder<T>&);
|
||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
// Interface of ValueHolder<T>
|
||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
template<class T>
|
||
|
class ValueHolder
|
||
|
{
|
||
|
public:
|
||
|
ValueHolder(char s,
|
||
|
const char* l,
|
||
|
T& b,
|
||
|
const char* desc,
|
||
|
bool mandatory);
|
||
|
ValueHolder(const char* l,
|
||
|
T& b,
|
||
|
const char* desc,
|
||
|
bool mandatory);
|
||
|
ValueHolder(char s,
|
||
|
T& b,
|
||
|
const char* desc,
|
||
|
bool mandatory);
|
||
|
friend argstream& operator>><>(argstream& s,const ValueHolder<T>& v);
|
||
|
std::string name() const;
|
||
|
std::string description() const;
|
||
|
private:
|
||
|
std::string shortName_;
|
||
|
std::string longName_;
|
||
|
T* value_;
|
||
|
T initialValue_;
|
||
|
std::string description_;
|
||
|
bool mandatory_;
|
||
|
};
|
||
|
template <class T>
|
||
|
inline ValueHolder<T>
|
||
|
parameter(char s,
|
||
|
const char* l,
|
||
|
T& b,
|
||
|
const char* desc="",
|
||
|
bool mandatory = true)
|
||
|
{
|
||
|
return ValueHolder<T>(s,l,b,desc,mandatory);
|
||
|
}
|
||
|
template <class T>
|
||
|
inline ValueHolder<T>
|
||
|
parameter(char s,
|
||
|
T& b,
|
||
|
const char* desc="",
|
||
|
bool mandatory = true)
|
||
|
{
|
||
|
return ValueHolder<T>(s,b,desc,mandatory);
|
||
|
}
|
||
|
template <class T>
|
||
|
inline ValueHolder<T>
|
||
|
parameter(const char* l,
|
||
|
T& b,
|
||
|
const char* desc="",
|
||
|
bool mandatory = true)
|
||
|
{
|
||
|
return ValueHolder<T>(l,b,desc,mandatory);
|
||
|
}
|
||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
// Interface of OptionHolder
|
||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
class OptionHolder
|
||
|
{
|
||
|
public:
|
||
|
inline OptionHolder(char s,
|
||
|
const char* l,
|
||
|
bool& b,
|
||
|
const char* desc);
|
||
|
inline OptionHolder(const char* l,
|
||
|
bool& b,
|
||
|
const char* desc);
|
||
|
inline OptionHolder(char s,
|
||
|
bool& b,
|
||
|
const char* desc);
|
||
|
friend argstream& operator>>(argstream& s,const OptionHolder& v);
|
||
|
inline std::string name() const;
|
||
|
inline std::string description() const;
|
||
|
protected:
|
||
|
inline OptionHolder(char s,
|
||
|
const char* l,
|
||
|
const char* desc);
|
||
|
friend OptionHolder help(char s='h',
|
||
|
const char* l="help",
|
||
|
const char* desc="Display this help");
|
||
|
private:
|
||
|
std::string shortName_;
|
||
|
std::string longName_;
|
||
|
bool* value_;
|
||
|
std::string description_;
|
||
|
};
|
||
|
inline OptionHolder
|
||
|
option(char s,
|
||
|
const char* l,
|
||
|
bool& b,
|
||
|
const char* desc="")
|
||
|
{
|
||
|
return OptionHolder(s,l,b,desc);
|
||
|
}
|
||
|
inline OptionHolder
|
||
|
option(char s,
|
||
|
bool& b,
|
||
|
const char* desc="")
|
||
|
{
|
||
|
return OptionHolder(s,b,desc);
|
||
|
}
|
||
|
inline OptionHolder
|
||
|
option(const char* l,
|
||
|
bool& b,
|
||
|
const char* desc="")
|
||
|
{
|
||
|
return OptionHolder(l,b,desc);
|
||
|
}
|
||
|
inline OptionHolder
|
||
|
help(char s,
|
||
|
const char* l,
|
||
|
const char* desc)
|
||
|
{
|
||
|
return OptionHolder(s,l,desc);
|
||
|
}
|
||
|
template <class T, class O>
|
||
|
class ValuesHolder;
|
||
|
template <typename T, typename O>
|
||
|
argstream& operator>> (argstream&, const ValuesHolder<T, O>&);
|
||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
// Interface of ValuesHolder
|
||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
template<class T,class O>
|
||
|
class ValuesHolder
|
||
|
{
|
||
|
public:
|
||
|
ValuesHolder(const O& o,
|
||
|
const char* desc,
|
||
|
int len);
|
||
|
friend argstream& operator>><>(argstream& s,const ValuesHolder<T,O>& v);
|
||
|
std::string name() const;
|
||
|
std::string description() const;
|
||
|
typedef T value_type;
|
||
|
private:
|
||
|
mutable O value_;
|
||
|
std::string description_;
|
||
|
int len_;
|
||
|
char letter_;
|
||
|
};
|
||
|
template<class T,class O>
|
||
|
inline ValuesHolder<T,O>
|
||
|
values(const O& o,
|
||
|
const char* desc="",
|
||
|
int len=-1)
|
||
|
{
|
||
|
return ValuesHolder<T,O>(o,desc,len);
|
||
|
}
|
||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
// Interface of ValueParser
|
||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
template <class T>
|
||
|
class ValueParser
|
||
|
{
|
||
|
public:
|
||
|
inline T operator()(const std::string& s) const
|
||
|
{
|
||
|
std::istringstream is(s);
|
||
|
T t;
|
||
|
is>>t;
|
||
|
return t;
|
||
|
}
|
||
|
};
|
||
|
// We need to specialize for string otherwise parsing of a value that
|
||
|
// contains space (for example a string with space passed in quotes on the
|
||
|
// command line) would parse only the first element of the value!!!
|
||
|
template <>
|
||
|
class ValueParser<std::string>
|
||
|
{
|
||
|
public:
|
||
|
inline std::string operator()(const std::string& s) const
|
||
|
{
|
||
|
return s;
|
||
|
}
|
||
|
};
|
||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
// Interface of argstream
|
||
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
class argstream
|
||
|
{
|
||
|
public:
|
||
|
inline argstream(int argc,char** argv);
|
||
|
//inline argstream(const char* c);
|
||
|
template<class T>
|
||
|
friend argstream& operator>>(argstream& s,const ValueHolder<T>& v);
|
||
|
friend inline argstream& operator>>(argstream& s,const OptionHolder& v);
|
||
|
template<class T,class O>
|
||
|
friend argstream& operator>>(argstream& s,const ValuesHolder<T,O>& v);
|
||
|
|
||
|
inline bool helpRequested() const;
|
||
|
inline bool isOk() const;
|
||
|
inline std::string errorLog() const;
|
||
|
inline std::string usage() const;
|
||
|
inline void defaultErrorHandling(bool ignoreUnused=false) const;
|
||
|
static inline char uniqueLetter();
|
||
|
protected:
|
||
|
void parse(int argc,char** argv);
|
||
|
private:
|
||
|
typedef std::list<std::string>::iterator value_iterator;
|
||
|
typedef std::pair<std::string,std::string> help_entry;
|
||
|
std::string progName_;
|
||
|
std::map<std::string,value_iterator> options_;
|
||
|
std::list<std::string> values_;
|
||
|
bool minusActive_;
|
||
|
bool isOk_;
|
||
|
std::deque<help_entry> argHelps_;
|
||
|
std::string cmdLine_;
|
||
|
std::deque<std::string> errors_;
|
||
|
bool helpRequested_;
|
||
|
};
|
||
|
//************************************************************
|
||
|
// Implementation of ValueHolder<T>
|
||
|
//************************************************************
|
||
|
template<class T>
|
||
|
ValueHolder<T>::ValueHolder(char s,
|
||
|
const char* l,
|
||
|
T& v,
|
||
|
const char* desc,
|
||
|
bool mandatory)
|
||
|
: shortName_(1,s),
|
||
|
longName_(l),
|
||
|
value_(&v),
|
||
|
initialValue_(v),
|
||
|
description_(desc),
|
||
|
mandatory_(mandatory)
|
||
|
{
|
||
|
}
|
||
|
template<class T>
|
||
|
ValueHolder<T>::ValueHolder(const char* l,
|
||
|
T& v,
|
||
|
const char* desc,
|
||
|
bool mandatory)
|
||
|
: longName_(l),
|
||
|
value_(&v),
|
||
|
initialValue_(v),
|
||
|
description_(desc),
|
||
|
mandatory_(mandatory)
|
||
|
{
|
||
|
}
|
||
|
template<class T>
|
||
|
ValueHolder<T>::ValueHolder(char s,
|
||
|
T& v,
|
||
|
const char* desc,
|
||
|
bool mandatory)
|
||
|
: shortName_(1,s),
|
||
|
value_(&v),
|
||
|
initialValue_(v),
|
||
|
description_(desc),
|
||
|
mandatory_(mandatory)
|
||
|
{
|
||
|
}
|
||
|
template<class T>
|
||
|
std::string
|
||
|
ValueHolder<T>::name() const
|
||
|
{
|
||
|
std::ostringstream os;
|
||
|
if (!shortName_.empty()) os<<'-'<<shortName_;
|
||
|
if (!longName_.empty()) {
|
||
|
if (!shortName_.empty()) os<<'/';
|
||
|
os<<"--"<<longName_;
|
||
|
}
|
||
|
return os.str();
|
||
|
}
|
||
|
template<class T>
|
||
|
std::string
|
||
|
ValueHolder<T>::description() const
|
||
|
{
|
||
|
std::ostringstream os;
|
||
|
os<<description_;
|
||
|
if (mandatory_)
|
||
|
{
|
||
|
os<<"(mandatory)";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
os<<"(default="<<initialValue_<<")";
|
||
|
}
|
||
|
return os.str();
|
||
|
}
|
||
|
//************************************************************
|
||
|
// Implementation of OptionHolder
|
||
|
//************************************************************
|
||
|
inline OptionHolder::OptionHolder(char s,
|
||
|
const char* l,
|
||
|
bool& b,
|
||
|
const char* desc)
|
||
|
: shortName_(1,s),
|
||
|
longName_(l),
|
||
|
value_(&b),
|
||
|
description_(desc)
|
||
|
{
|
||
|
}
|
||
|
inline OptionHolder::OptionHolder(const char* l,
|
||
|
bool& b,
|
||
|
const char* desc)
|
||
|
: longName_(l),
|
||
|
value_(&b),
|
||
|
description_(desc)
|
||
|
{
|
||
|
}
|
||
|
inline OptionHolder::OptionHolder(char s,
|
||
|
bool& b,
|
||
|
const char* desc)
|
||
|
: shortName_(1,s),
|
||
|
value_(&b),
|
||
|
description_(desc)
|
||
|
{
|
||
|
}
|
||
|
inline OptionHolder::OptionHolder(char s,
|
||
|
const char* l,
|
||
|
const char* desc)
|
||
|
: shortName_(1,s),
|
||
|
longName_(l),
|
||
|
value_(NULL),
|
||
|
description_(desc)
|
||
|
{
|
||
|
}
|
||
|
inline std::string
|
||
|
OptionHolder::name() const
|
||
|
{
|
||
|
std::ostringstream os;
|
||
|
if (!shortName_.empty()) os<<'-'<<shortName_;
|
||
|
if (!longName_.empty())
|
||
|
{
|
||
|
if (!shortName_.empty()) os<<'/';
|
||
|
os<<"--"<<longName_;
|
||
|
}
|
||
|
return os.str();
|
||
|
}
|
||
|
inline std::string
|
||
|
OptionHolder::description() const
|
||
|
{
|
||
|
return description_;
|
||
|
}
|
||
|
//************************************************************
|
||
|
// Implementation of ValuesHolder<T,O>
|
||
|
//************************************************************
|
||
|
template<class T,class O>
|
||
|
ValuesHolder<T,O>::ValuesHolder(const O& o,
|
||
|
const char* desc,
|
||
|
int len)
|
||
|
: value_(o),
|
||
|
description_(desc),
|
||
|
len_(len)
|
||
|
{
|
||
|
letter_ = argstream::uniqueLetter();
|
||
|
}
|
||
|
template <class T,class O>
|
||
|
std::string
|
||
|
ValuesHolder<T,O>::name() const
|
||
|
{
|
||
|
std::ostringstream os;
|
||
|
os<<letter_<<"i";
|
||
|
return os.str();
|
||
|
}
|
||
|
template <class T,class O>
|
||
|
std::string
|
||
|
ValuesHolder<T,O>::description() const
|
||
|
{
|
||
|
return description_;
|
||
|
}
|
||
|
//************************************************************
|
||
|
// Implementation of argstream
|
||
|
//************************************************************
|
||
|
inline
|
||
|
argstream::argstream(int argc,char** argv)
|
||
|
: progName_(argv[0]),
|
||
|
minusActive_(true),
|
||
|
isOk_(true)
|
||
|
{
|
||
|
parse(argc,argv);
|
||
|
}
|
||
|
//inline
|
||
|
// argstream::argstream(const char* c)
|
||
|
// : progName_(""),
|
||
|
// minusActive_(true),
|
||
|
// isOk_(true)
|
||
|
//{
|
||
|
// std::string s(c);
|
||
|
// // Build argc, argv from s. We must add a dummy first element for
|
||
|
// // progName because parse() expects it!!
|
||
|
// std::deque<std::string> args;
|
||
|
// args.push_back("");
|
||
|
// std::istringstream is(s);
|
||
|
// while (is.good())
|
||
|
// {
|
||
|
// std::string t;
|
||
|
// is>>t;
|
||
|
// args.push_back(t);
|
||
|
// }
|
||
|
// char* pargs[args.size()];
|
||
|
// char** p = pargs;
|
||
|
// for (std::deque<std::string>::const_iterator
|
||
|
// iter = args.begin();
|
||
|
// iter != args.end();++iter)
|
||
|
// {
|
||
|
// *p++ = const_cast<char*>(iter->c_str());
|
||
|
// }
|
||
|
// parse(args.size(),pargs);
|
||
|
//}
|
||
|
inline void
|
||
|
argstream::parse(int argc,char** argv)
|
||
|
{
|
||
|
// Run thru all arguments.
|
||
|
// * it has -- in front : it is a long name option, if remainder is empty,
|
||
|
// it is an error
|
||
|
// * it has - in front : it is a sequence of short name options, if
|
||
|
// remainder is empty, deactivates option (- will
|
||
|
// now be considered a char).
|
||
|
// * if any other char, or if option was deactivated
|
||
|
// : it is a value. Values are split in parameters
|
||
|
// (immediately follow an option) and pure values.
|
||
|
// Each time a value is parsed, if the previously parsed argument was an
|
||
|
// option, then the option is linked to the value in case of it is a
|
||
|
// option with parameter. The subtle point is that when several options
|
||
|
// are given with short names (ex: -abc equivalent to -a -b -c), the last
|
||
|
// parsed option is -c).
|
||
|
// Since we use map for option, any successive call overides the previous
|
||
|
// one: foo -a -b -a hello is equivalent to foo -b -a hello
|
||
|
// For values it is not true since we might have several times the same
|
||
|
// value.
|
||
|
value_iterator* lastOption = NULL;
|
||
|
for (char** a = argv,**astop=a+argc;++a!=astop;)
|
||
|
{
|
||
|
std::string s(*a);
|
||
|
if (minusActive_ && s[0] == '-')
|
||
|
{
|
||
|
if (s.size() > 1 && s[1] == '-')
|
||
|
{
|
||
|
if (s.size() == 2)
|
||
|
{
|
||
|
minusActive_ = false;
|
||
|
continue;
|
||
|
}
|
||
|
lastOption = &(options_[s.substr(2)] = values_.end());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (s.size() > 1)
|
||
|
{
|
||
|
// Parse all chars, if it is a minus we have an error
|
||
|
for (std::string::const_iterator cter = s.begin();
|
||
|
++cter != s.end();)
|
||
|
{
|
||
|
if (*cter == '-')
|
||
|
{
|
||
|
isOk_ = false;
|
||
|
std::ostringstream os;
|
||
|
os<<"- in the middle of a switch "<<a;
|
||
|
errors_.push_back(os.str());
|
||
|
break;
|
||
|
}
|
||
|
lastOption = &(options_[std::string(1,*cter)] = values_.end());
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
isOk_ = false;
|
||
|
errors_.push_back("Invalid argument -");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
values_.push_back(s);
|
||
|
if (lastOption != NULL)
|
||
|
{
|
||
|
*lastOption = --values_.end();
|
||
|
}
|
||
|
lastOption = NULL;
|
||
|
}
|
||
|
}
|
||
|
#ifdef ARGSTREAM_DEBUG
|
||
|
for (std::map<std::string,value_iterator>::const_iterator
|
||
|
iter = options_.begin();iter != options_.end();++iter)
|
||
|
{
|
||
|
std::cout<<"DEBUG: option "<<iter->first;
|
||
|
if (iter->second != values_.end())
|
||
|
{
|
||
|
std::cout<<" -> "<<*(iter->second);
|
||
|
}
|
||
|
std::cout<<std::endl;
|
||
|
}
|
||
|
for (std::list<std::string>::const_iterator
|
||
|
iter = values_.begin();iter != values_.end();++iter)
|
||
|
{
|
||
|
std::cout<<"DEBUG: value "<<*iter<<std::endl;
|
||
|
}
|
||
|
#endif // ARGSTREAM_DEBUG
|
||
|
}
|
||
|
inline bool
|
||
|
argstream::isOk() const
|
||
|
{
|
||
|
return isOk_;
|
||
|
}
|
||
|
inline bool
|
||
|
argstream::helpRequested() const
|
||
|
{
|
||
|
return helpRequested_;
|
||
|
}
|
||
|
inline std::string
|
||
|
argstream::usage() const
|
||
|
{
|
||
|
std::ostringstream os;
|
||
|
os<<"usage: "<<progName_<<cmdLine_<<'\n';
|
||
|
unsigned int lmax = 0;
|
||
|
for (std::deque<help_entry>::const_iterator
|
||
|
iter = argHelps_.begin();iter != argHelps_.end();++iter)
|
||
|
{
|
||
|
if (lmax<iter->first.size()) lmax = iter->first.size();
|
||
|
}
|
||
|
for (std::deque<help_entry>::const_iterator
|
||
|
iter = argHelps_.begin();iter != argHelps_.end();++iter)
|
||
|
{
|
||
|
os<<'\t'<<iter->first<<std::string(lmax-iter->first.size(),' ')
|
||
|
<<" : "<<iter->second<<'\n';
|
||
|
}
|
||
|
return os.str();
|
||
|
}
|
||
|
inline std::string
|
||
|
argstream::errorLog() const
|
||
|
{
|
||
|
std::string s;
|
||
|
for(std::deque<std::string>::const_iterator iter = errors_.begin();
|
||
|
iter != errors_.end();++iter)
|
||
|
{
|
||
|
s += *iter;
|
||
|
s += '\n';
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
inline char
|
||
|
argstream::uniqueLetter()
|
||
|
{
|
||
|
static unsigned int c = 'a';
|
||
|
return c++;
|
||
|
}
|
||
|
template<class T>
|
||
|
argstream&
|
||
|
operator>>(argstream& s,const ValueHolder<T>& v)
|
||
|
{
|
||
|
// Search in the options if there is any such option defined either with a
|
||
|
// short name or a long name. If both are found, only the last one is
|
||
|
// used.
|
||
|
#ifdef ARGSTREAM_DEBUG
|
||
|
std::cout<<"DEBUG: searching "<<v.shortName_<<" "<<v.longName_<<std::endl;
|
||
|
#endif
|
||
|
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||
|
if (v.mandatory_)
|
||
|
{
|
||
|
if (!v.shortName_.empty())
|
||
|
{
|
||
|
s.cmdLine_ += " -";
|
||
|
s.cmdLine_ += v.shortName_;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s.cmdLine_ += " --";
|
||
|
s.cmdLine_ += v.longName_;
|
||
|
}
|
||
|
s.cmdLine_ += " value";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!v.shortName_.empty())
|
||
|
{
|
||
|
s.cmdLine_ += " [-";
|
||
|
s.cmdLine_ += v.shortName_;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s.cmdLine_ += " [--";
|
||
|
s.cmdLine_ += v.longName_;
|
||
|
}
|
||
|
s.cmdLine_ += " value]";
|
||
|
|
||
|
}
|
||
|
std::map<std::string,argstream::value_iterator>::iterator iter =
|
||
|
s.options_.find(v.shortName_);
|
||
|
if (iter == s.options_.end())
|
||
|
{
|
||
|
iter = s.options_.find(v.longName_);
|
||
|
}
|
||
|
if (iter != s.options_.end())
|
||
|
{
|
||
|
// If we find counterpart for value holder on command line, either it
|
||
|
// has an associated value in which case we assign it, or it has not, in
|
||
|
// which case we have an error.
|
||
|
if (iter->second != s.values_.end())
|
||
|
{
|
||
|
#ifdef ARGSTREAM_DEBUG
|
||
|
std::cout<<"DEBUG: found value "<<*(iter->second)<<std::endl;
|
||
|
#endif
|
||
|
ValueParser<T> p;
|
||
|
*(v.value_) = p(*(iter->second));
|
||
|
// The option and its associated value are removed, the subtle thing
|
||
|
// is that someother options might have this associated value too,
|
||
|
// which we must invalidate.
|
||
|
s.values_.erase(iter->second);
|
||
|
|
||
|
// FIXME this loop seems to crash if a std::string is used as the value
|
||
|
//for (std::map<std::string,argstream::value_iterator>::iterator
|
||
|
// jter = s.options_.begin();jter != s.options_.end();++jter)
|
||
|
//{
|
||
|
// if (jter->second == iter->second)
|
||
|
// {
|
||
|
// jter->second = s.values_.end();
|
||
|
// }
|
||
|
//}
|
||
|
s.options_.erase(iter);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s.isOk_ = false;
|
||
|
std::ostringstream os;
|
||
|
os<<"No value following switch "<<iter->first
|
||
|
<<" on command line";
|
||
|
s.errors_.push_back(os.str());
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (v.mandatory_)
|
||
|
{
|
||
|
s.isOk_ = false;
|
||
|
std::ostringstream os;
|
||
|
os<<"Mandatory parameter ";
|
||
|
if (!v.shortName_.empty()) os<<'-'<<v.shortName_;
|
||
|
if (!v.longName_.empty())
|
||
|
{
|
||
|
if (!v.shortName_.empty()) os<<'/';
|
||
|
os<<"--"<<v.longName_;
|
||
|
}
|
||
|
os<<" missing";
|
||
|
s.errors_.push_back(os.str());
|
||
|
}
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
inline argstream&
|
||
|
operator>>(argstream& s,const OptionHolder& v)
|
||
|
{
|
||
|
// Search in the options if there is any such option defined either with a
|
||
|
// short name or a long name. If both are found, only the last one is
|
||
|
// used.
|
||
|
#ifdef ARGSTREAM_DEBUG
|
||
|
std::cout<<"DEBUG: searching "<<v.shortName_<<" "<<v.longName_<<std::endl;
|
||
|
#endif
|
||
|
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||
|
{
|
||
|
std::string c;
|
||
|
if (!v.shortName_.empty())
|
||
|
{
|
||
|
c += " [-";
|
||
|
c += v.shortName_;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
c += " [--";
|
||
|
c += v.longName_;
|
||
|
}
|
||
|
c += "]";
|
||
|
s.cmdLine_ = c+s.cmdLine_;
|
||
|
}
|
||
|
std::map<std::string,argstream::value_iterator>::iterator iter =
|
||
|
s.options_.find(v.shortName_);
|
||
|
if (iter == s.options_.end())
|
||
|
{
|
||
|
iter = s.options_.find(v.longName_);
|
||
|
}
|
||
|
if (iter != s.options_.end())
|
||
|
{
|
||
|
// If we find counterpart for value holder on command line then the
|
||
|
// option is true and if an associated value was found, it is ignored
|
||
|
if (v.value_ != NULL)
|
||
|
{
|
||
|
*(v.value_) = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s.helpRequested_ = true;
|
||
|
}
|
||
|
// The option only is removed
|
||
|
s.options_.erase(iter);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (v.value_ != NULL)
|
||
|
{
|
||
|
*(v.value_) = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
s.helpRequested_ = false;
|
||
|
}
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
template<class T,class O>
|
||
|
argstream&
|
||
|
operator>>(argstream& s,const ValuesHolder<T,O>& v)
|
||
|
{
|
||
|
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||
|
{
|
||
|
std::ostringstream os;
|
||
|
os<<' '<<v.letter_<<'1';
|
||
|
switch (v.len_)
|
||
|
{
|
||
|
case -1:
|
||
|
os<<"...";
|
||
|
break;
|
||
|
case 1:
|
||
|
break;
|
||
|
default:
|
||
|
os<<"..."<<v.letter_<<v.len_;
|
||
|
break;
|
||
|
}
|
||
|
s.cmdLine_ += os.str();
|
||
|
}
|
||
|
std::list<std::string>::iterator first = s.values_.begin();
|
||
|
// We add to the iterator as much values as we can, limited to the length
|
||
|
// specified (if different of -1)
|
||
|
int n = v.len_ != -1?v.len_:s.values_.size();
|
||
|
while (first != s.values_.end() && n-->0)
|
||
|
{
|
||
|
// Read the value from the string *first
|
||
|
ValueParser<T> p;
|
||
|
*(v.value_++) = p(*first );
|
||
|
s.argHelps_.push_back(argstream::help_entry(v.name(),v.description()));
|
||
|
// The value we just removed was maybe "remembered" by an option so we
|
||
|
// remove it now.
|
||
|
for (std::map<std::string,argstream::value_iterator>::iterator
|
||
|
jter = s.options_.begin();jter != s.options_.end();++jter)
|
||
|
{
|
||
|
if (jter->second == first)
|
||
|
{
|
||
|
jter->second = s.values_.end();
|
||
|
}
|
||
|
}
|
||
|
++first;
|
||
|
}
|
||
|
// Check if we have enough values
|
||
|
if (n != 0)
|
||
|
{
|
||
|
s.isOk_ = false;
|
||
|
std::ostringstream os;
|
||
|
os<<"Expecting "<<v.len_<<" values";
|
||
|
s.errors_.push_back(os.str());
|
||
|
}
|
||
|
// Erase the values parsed
|
||
|
s.values_.erase(s.values_.begin(),first);
|
||
|
return s;
|
||
|
}
|
||
|
inline void
|
||
|
argstream::defaultErrorHandling(bool ignoreUnused) const
|
||
|
{
|
||
|
if (helpRequested_)
|
||
|
{
|
||
|
std::cout<<usage();
|
||
|
exit(1);
|
||
|
}
|
||
|
if (!isOk_)
|
||
|
{
|
||
|
std::cerr<<errorLog();
|
||
|
exit(1);
|
||
|
}
|
||
|
if (!ignoreUnused &&
|
||
|
(!values_.empty() || !options_.empty()))
|
||
|
{
|
||
|
std::cerr<<"Unused arguments"<<std::endl;
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
#endif // ARGSTREAM_H
|
||
|
|