Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F93133371
argstream.h
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Nov 26, 11:14
Size
20 KB
Mime Type
text/x-c
Expires
Thu, Nov 28, 11:14 (1 d, 21 h)
Engine
blob
Format
Raw Data
Handle
22581663
Attached To
R6621 SBCP High-Level Driver
argstream.h
View Options
/* Copyright (C) 2004 Xavier D�coret <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 <stdlib.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);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 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= new char*[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);
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
Event Timeline
Log In to Comment