687 lines
22 KiB
C++
687 lines
22 KiB
C++
![]() |
#include <mrw/exception.hpp>
|
||
|
#include <mrw/stacktrace.hpp>
|
||
|
#include <mrw/smartpointer.hpp>
|
||
|
#include <mrw/simpletrace.hpp>
|
||
|
#include <stdlib.h> // exit
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
#include <set>
|
||
|
#include <list>
|
||
|
#include <exception>
|
||
|
#include <stdexcept>
|
||
|
#include <sstream>
|
||
|
#include <iostream>
|
||
|
|
||
|
namespace mrw {
|
||
|
|
||
|
/** @defgroup arguments C++ Evaluation of Command Line Arguments
|
||
|
|
||
|
@brief These classes do simple and easy command line argment evaluation
|
||
|
in C++.
|
||
|
|
||
|
Features:
|
||
|
- every argument has a long and a short option
|
||
|
- all arguments are optional and provide a default value
|
||
|
- the order of options is not important
|
||
|
- every option can take any (fixed) number of additional parameter of
|
||
|
type
|
||
|
- string
|
||
|
- integer
|
||
|
- boolean (@c "yes", @c "on", @c "true" evaluates to @c true)
|
||
|
- short options can be combined, instead of
|
||
|
@c -a @c -b @c -c @c 15 you can simply write @c -abc @c 15
|
||
|
- automated help display (support for option @c -h)
|
||
|
|
||
|
@c mrw::Args is the main user interface class that represents
|
||
|
all command line options with their arguments. It is implemented
|
||
|
as singleton, so the same instance can be accessed from
|
||
|
everywhere in the code. It mst be setup just in the beginning of
|
||
|
the @c main() function.
|
||
|
|
||
|
The other important class for the end user is @c mrw::Opt, one
|
||
|
possible option with additional parameter. The end user needs @c
|
||
|
mrw::Opt to setup all allowed command line options in the
|
||
|
beginning, bevore evaluation of the user given command line is
|
||
|
done (before @c argc and @c argv is shifted into @c mrw::Args.
|
||
|
|
||
|
The third class a user should know is @c mrw::Param. It
|
||
|
represents the arguments to one option. Every instance of @c
|
||
|
mrw::Opt owns one instance of @c mrw::Param that is either empty
|
||
|
or list of (mandatory) arguments of type @c std::string, @c int
|
||
|
or @c bool.
|
||
|
|
||
|
The classes are normally used this way:
|
||
|
|
||
|
@code
|
||
|
// this program may be called e.g. with the following arguments:
|
||
|
// ./a.out --coordinates 13 1 -vo out.txt -n MyName
|
||
|
int main(int argv, const char * const * const argv) {
|
||
|
try {
|
||
|
mrw::Args::instance()
|
||
|
// setup the possible options
|
||
|
<<mrw::Opt('h', "--help", "Show this help text")
|
||
|
<<mrw::Opt('v', "--verbose", "print more information")
|
||
|
<<mrw::Opt('q', "--quiet", "be quiet")
|
||
|
<<mrw::Opt('n', "--name", mrw::Param()<<"MRW", "name of the user")
|
||
|
<<mrw::Opt('o', "--output-file", mrw::Param()<<"", "file to load")
|
||
|
<<mrw::Opt('c', "--coordinates", mrw::Param()<<0<<0, "X, Y coordinate")
|
||
|
// set a description text for help
|
||
|
<<"This is a testprogram for argument evaluation in C++"
|
||
|
// define the help option
|
||
|
<<'h'
|
||
|
// shift in the command line arguments
|
||
|
<<argc<<argv;
|
||
|
...
|
||
|
// example usage of simple option
|
||
|
if (mrw::Args::instance().find('v')) // be verbose here
|
||
|
...
|
||
|
// example usage of option with (one) parameter
|
||
|
ifstream file(mrw::Args::instance().find('o').toString().c_str());
|
||
|
...
|
||
|
return 0
|
||
|
}
|
||
|
} catch (mrw::exception& x) {
|
||
|
// trace error, print help or mention option -h
|
||
|
}
|
||
|
}
|
||
|
@endcode
|
||
|
*/
|
||
|
//@{
|
||
|
|
||
|
/** @brief List of additional (mandatory) parameter to one command
|
||
|
line argument.
|
||
|
@pre #include<mrw/arg.hpp>
|
||
|
|
||
|
A new mandatory parameter is added to the list of parameter, by
|
||
|
shifting the default value into the instance of @c
|
||
|
mrw::Param. E.g. add a string, that defaults to @c "noname", an
|
||
|
integer, that defaults to @c 4, another integer that defaults to
|
||
|
@2 and a boolean that defaults to @c "true":
|
||
|
|
||
|
@code
|
||
|
// if you need the instance as variable:
|
||
|
mrw::Param p();
|
||
|
p<<"noname"<<4<<2<<true;
|
||
|
// or in an expression:
|
||
|
mrw::Opt o('e', "--example", mrw::Param()<<"noname"<<4<<2<<true, "");
|
||
|
@endcode
|
||
|
|
||
|
To access a value at a given position, simply use @c
|
||
|
operator[]. Then use @c mrw::Value::toString, @c
|
||
|
mrw::Value::toInt or @c mrw::Value::toBool to get the value of
|
||
|
that parameter. Of course yo must know the correct type of a
|
||
|
parameter at a given position, but since you are the programmer
|
||
|
you know it, or you can get it by running your program with the
|
||
|
help option, mostly @c -h. To retrieve the parameters setup in
|
||
|
the example above (connected to option @c -e or @c --example),
|
||
|
either the default value, or the value overwritten by the user,
|
||
|
simply type:
|
||
|
|
||
|
@code
|
||
|
mrw::Args& args = mrw::Args::instance();
|
||
|
std::string theString = args[0]->toString();
|
||
|
int firstInteger = args[1]->toInt();
|
||
|
int secondInteger = args[2]->toInt();
|
||
|
bool theBoolean = args[3]->toBool();
|
||
|
@endcode
|
||
|
|
||
|
@section argParts Setup Command Line from Different Program Parts
|
||
|
|
||
|
If your software is large and splitted into different parts (or
|
||
|
sub projects or modules, ...), all with their own parameter, you
|
||
|
can use the following trick: Statical variables are initialized
|
||
|
before the @c main() function is called.
|
||
|
|
||
|
In part Abc write in a code file (not in a header file):
|
||
|
|
||
|
@code
|
||
|
class AbcArguments {
|
||
|
public:
|
||
|
AbcArguments() {
|
||
|
mrw::Args::instance()
|
||
|
<<mrw::Opt('n', "--name", mrw::Param()<<"MRW", "name of the user")
|
||
|
<<mrw::Opt('o', "--output-file", mrw::Param()<<"", "file to load")
|
||
|
<<mrw::Opt('c', "--coordinates", mrw::Param()<<0<<0,
|
||
|
"X, Y coordinate")
|
||
|
<<"Description text for part Abc, will be added to the\n"
|
||
|
"overall documentation";
|
||
|
}
|
||
|
};
|
||
|
static AbcArgument abcArgumentInitializer;
|
||
|
@endcode
|
||
|
|
||
|
Do the same for all other parts Then the @c main() function reduces to:
|
||
|
|
||
|
@code
|
||
|
int main(int argc, const char * const * const argv) {
|
||
|
// set the help and evaluate the user given arguments
|
||
|
mrw::Args::instance()
|
||
|
<<mrw::Opt('h', "--help", "Show this help text")
|
||
|
<<'h'<<argc<<argv;
|
||
|
...
|
||
|
}
|
||
|
@endcode
|
||
|
*/
|
||
|
class Param {
|
||
|
|
||
|
public:
|
||
|
|
||
|
/** @brief Abstract base class to represent one single parameter value.
|
||
|
@pre #include<mrw/arg.hpp>
|
||
|
*/
|
||
|
class Value {
|
||
|
|
||
|
public:
|
||
|
|
||
|
virtual ~Value() {}
|
||
|
|
||
|
/** @brief If the instance is a @c std::string, return that
|
||
|
string, otherwise throw an exception.
|
||
|
@throw mrw::bad_cast if the instance is not a string
|
||
|
@return the string, if the instance is a string
|
||
|
*/
|
||
|
virtual const std::string& toString() const throw(mrw::exception) {
|
||
|
throw mrw::bad_cast();
|
||
|
}
|
||
|
|
||
|
/** @brief If the instance is an @c int, return that integer,
|
||
|
otherwise throw an exception.
|
||
|
@throw mrw::bad_cast if the instance is not a integer
|
||
|
@return the integer, if the instance is a integer
|
||
|
*/
|
||
|
virtual int toInt() const throw(mrw::exception) {
|
||
|
throw mrw::bad_cast();
|
||
|
}
|
||
|
|
||
|
/** @brief If the instance is an @c bool, return that boolean,
|
||
|
otherwise throw an exception.
|
||
|
@note the following typings are converted to @c true:
|
||
|
- true
|
||
|
- yes
|
||
|
- on
|
||
|
Everything else is converted to @c false.
|
||
|
@throw mrw::bad_cast if the instance is not a boolean
|
||
|
@return the boolean, if the instance is a boolean
|
||
|
*/
|
||
|
virtual bool toBool() const throw(mrw::exception) {
|
||
|
throw mrw::bad_cast();
|
||
|
}
|
||
|
|
||
|
/// @brief returns a printable representation of the value
|
||
|
virtual std::string printable() const throw(mrw::bad_exception) = 0;
|
||
|
|
||
|
/// @brief returns a printable typename of the value
|
||
|
virtual const std::string& typestr() const throw(mrw::bad_exception)=0;
|
||
|
|
||
|
protected:
|
||
|
friend class Args; // allow assign for Param
|
||
|
virtual void operator=(const std::string&) throw(mrw::exception) = 0;
|
||
|
};
|
||
|
|
||
|
private:
|
||
|
|
||
|
class StringValue: public Value {
|
||
|
public:
|
||
|
virtual ~StringValue() {}
|
||
|
StringValue(const std::string& s) throw(mrw::bad_exception): _s(s) {
|
||
|
}
|
||
|
virtual const std::string& toString() const throw(mrw::exception) {
|
||
|
return _s;
|
||
|
}
|
||
|
virtual const std::string& typestr() const throw(mrw::bad_exception) {
|
||
|
static std::string name("string");
|
||
|
return name;
|
||
|
}
|
||
|
virtual std::string printable() const throw(mrw::bad_exception) {
|
||
|
return _s;
|
||
|
}
|
||
|
protected:
|
||
|
virtual void operator=(const std::string& s) throw(mrw::exception) {
|
||
|
_s = s;
|
||
|
}
|
||
|
private:
|
||
|
std::string _s;
|
||
|
};
|
||
|
|
||
|
class IntValue: public Value {
|
||
|
public:
|
||
|
virtual ~IntValue() {}
|
||
|
IntValue(int i) throw(mrw::bad_exception): _i(i) {
|
||
|
}
|
||
|
virtual int toInt() const throw(mrw::exception) {
|
||
|
return _i;
|
||
|
}
|
||
|
virtual const std::string& typestr() const throw(mrw::bad_exception) {
|
||
|
static std::string name("integer");
|
||
|
return name;
|
||
|
}
|
||
|
virtual std::string printable() const throw(mrw::bad_exception) {
|
||
|
return ((std::stringstream&)(std::stringstream()<<_i)).str();
|
||
|
}
|
||
|
protected:
|
||
|
virtual void operator=(const std::string& s) throw(mrw::exception) {
|
||
|
if (!(std::stringstream(s)>>_i)) throw mrw::bad_cast();
|
||
|
}
|
||
|
private:
|
||
|
int _i;
|
||
|
};
|
||
|
|
||
|
class BoolValue: public Value {
|
||
|
public:
|
||
|
virtual ~BoolValue() {}
|
||
|
BoolValue(bool b) throw(mrw::bad_exception): _b(b) {
|
||
|
}
|
||
|
virtual bool toBool() const throw(mrw::exception) {
|
||
|
return _b;
|
||
|
}
|
||
|
virtual const std::string& typestr() const throw(mrw::bad_exception) {
|
||
|
static std::string name("boolean (\"yes\" or \"no\")");
|
||
|
return name;
|
||
|
}
|
||
|
virtual std::string printable() const throw(mrw::bad_exception) {
|
||
|
return _b?"yes":"no";
|
||
|
}
|
||
|
protected:
|
||
|
virtual void operator=(const std::string& s) throw(mrw::exception) {
|
||
|
_b = s=="true" || s=="yes" || s=="on";
|
||
|
}
|
||
|
private:
|
||
|
bool _b;
|
||
|
};
|
||
|
|
||
|
typedef std::vector< mrw::SmartPointer<Value> > Params;
|
||
|
Params _params;
|
||
|
|
||
|
public:
|
||
|
|
||
|
/// @brief returns the number of (mandatory) parameter
|
||
|
int size() const throw(std::bad_exception) {
|
||
|
return _params.size();
|
||
|
}
|
||
|
|
||
|
/// @brief add one more mandatory string parameter
|
||
|
Param& operator<<(const char* const s) throw(mrw::bad_exception) {
|
||
|
_params.push_back(new StringValue(s));
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
/// @brief add one more mandatory string parameter
|
||
|
Param& operator<<(const std::string& s) throw(mrw::bad_exception) {
|
||
|
_params.push_back(new StringValue(s));
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
/// @brief add one more mandatory integer parameter
|
||
|
Param& operator<<(int i) throw(mrw::bad_exception) {
|
||
|
_params.push_back(new IntValue(i));
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
// @brief add one more mandatory boolean parameter
|
||
|
Param& operator<<(bool b) throw(mrw::bad_exception) {
|
||
|
_params.push_back(new BoolValue(b));
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
/** @brief get parameter number @i
|
||
|
@throw mrw::out_of_range if @c i is too big */
|
||
|
const mrw::SmartPointer<Value>& operator[](unsigned int i) const
|
||
|
throw(mrw::exception) {
|
||
|
if (i<_params.size()) return _params[i];
|
||
|
throw mrw::out_of_range
|
||
|
(((std::stringstream&)
|
||
|
(std::stringstream()<<"check failed: "
|
||
|
<<i<<'<'<<_params.size())).str());
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
|
||
|
friend class Args; // allow set
|
||
|
mrw::SmartPointer<Value>& setable(unsigned int i)
|
||
|
throw(mrw::exception) {
|
||
|
if (i<_params.size()) return _params[i];
|
||
|
throw mrw::out_of_range
|
||
|
(((std::stringstream&)
|
||
|
(std::stringstream()<<"check failed: "
|
||
|
<<i<<'<'<<_params.size())).str());
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
/** @brief this class represents one command line option
|
||
|
@pre #include<mrw/arg.hpp>
|
||
|
|
||
|
The library user needs this class when setting up the list of
|
||
|
supported command line ooptions: Simply shift one instance of @c
|
||
|
mrw::Opt per supported command line option into @c
|
||
|
mrw::Args::instance(), e.g.:
|
||
|
|
||
|
@code
|
||
|
mrw::Args::instance()
|
||
|
<<mrw::Opt('h', "--help", "Show this help text");
|
||
|
@endcode
|
||
|
*/
|
||
|
class Opt {
|
||
|
|
||
|
public:
|
||
|
|
||
|
/** @brief create an @c mrw::Opt with additional parameter
|
||
|
@param shortname short name of the option
|
||
|
@param longname long name of the option, must start with "--"
|
||
|
@param param the additional parameter
|
||
|
@param help the help string for this option
|
||
|
*/
|
||
|
Opt::Opt(const char shortname, const std::string& longname,
|
||
|
const Param& param, const std::string& help)
|
||
|
throw(mrw::bad_exception):
|
||
|
_set(false), _shortname(shortname), _longname(longname),
|
||
|
_param(param), _help(help) {
|
||
|
}
|
||
|
|
||
|
/** @brief create a simple @c mrw::Opt
|
||
|
|
||
|
This option is either set or not set, there are no additional
|
||
|
parameter.
|
||
|
|
||
|
@param shortname short name of the option
|
||
|
@param longname long name of the option, must start with "--"
|
||
|
@param help the help string for this option
|
||
|
*/
|
||
|
Opt::Opt(const char shortname, const std::string& longname,
|
||
|
const std::string& help)
|
||
|
throw(mrw::bad_exception):
|
||
|
_set(false), _shortname(shortname), _longname(longname),
|
||
|
_help(help) {
|
||
|
}
|
||
|
|
||
|
/** @brief get the help text for this option */
|
||
|
const std::string& help() const throw(mrw::bad_exception) {
|
||
|
return _help;
|
||
|
}
|
||
|
|
||
|
/** @brief find out, whether this option was set by the user
|
||
|
|
||
|
Example: Check whether the user has set the @c -v option for
|
||
|
verbose output:
|
||
|
|
||
|
@code
|
||
|
if (mrw::Args::instance().find('v')) // -v is set
|
||
|
@endcode
|
||
|
|
||
|
@return
|
||
|
- @c true if the user has started the program with this option
|
||
|
- @c false if the user has not set this option
|
||
|
*/
|
||
|
operator bool() const throw(std::bad_exception) {return _set;}
|
||
|
|
||
|
/** @brief get one of the additional parameter
|
||
|
|
||
|
If this option has additional parameter, get the @c i-th of them.
|
||
|
|
||
|
@throw mrw::out_of_range if @c i is too big
|
||
|
@param i number of the additional parameter to get (starting with @c 0)
|
||
|
@return a smart pointer to the value (default or given by the user)
|
||
|
*/
|
||
|
const mrw::SmartPointer<Param::Value>& operator[](unsigned int i) const
|
||
|
throw(mrw::exception) {
|
||
|
return _param[i];
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
|
||
|
friend class Args; // is allowed to set values
|
||
|
void set() const throw(mrw::bad_exception) {
|
||
|
_set = true;
|
||
|
}
|
||
|
Param& args() const throw(mrw::bad_exception) {
|
||
|
return _param;
|
||
|
}
|
||
|
mutable bool _set;
|
||
|
char _shortname;
|
||
|
std::string _longname;
|
||
|
mutable Param _param;
|
||
|
std::string _help;
|
||
|
};
|
||
|
|
||
|
/** @brief handle command line arguments
|
||
|
@pre #include<mrw/arg.hpp>
|
||
|
|
||
|
This class handles command line arguments. It is a
|
||
|
singleton. Get the one and only instance of this class with @c
|
||
|
mrw::Args::instance(). It is setup by shifting values into this
|
||
|
class. The order is important, be sure that you shift in @c argc
|
||
|
and @c argv as last parameters.
|
||
|
|
||
|
Example setup:
|
||
|
|
||
|
@code
|
||
|
mrw::Args::instance()
|
||
|
<<mrw::Opt('h', "--help", "Show this help text")
|
||
|
<<mrw::Opt('v', "--verbose", "print more information")
|
||
|
<<"This is a testprogram for argument evaluation in C++"
|
||
|
<<'h'<<argc<<argv;
|
||
|
@endcode
|
||
|
*/
|
||
|
class Args {
|
||
|
|
||
|
public:
|
||
|
|
||
|
typedef std::list<std::string> OtherArgs;
|
||
|
|
||
|
/// @brief get the one and only instance
|
||
|
static Args& instance() throw(mrw::bad_exception) { // singleton
|
||
|
static Args _instance;
|
||
|
return _instance;
|
||
|
}
|
||
|
|
||
|
/** @brief setup an acceptable option
|
||
|
|
||
|
Setup an acceptable user option.
|
||
|
|
||
|
Example:
|
||
|
|
||
|
@code
|
||
|
mrw::Args::instance()
|
||
|
<<mrw::Opt('v', "--verbose", "print more information");
|
||
|
@endcode
|
||
|
*/
|
||
|
Args& operator<<(const mrw::Opt& opt) throw(mrw::invalid_argument) {
|
||
|
// twice the same, but other sort order
|
||
|
Options::iterator it(_options.insert(_options.end(), opt));
|
||
|
if (!_shortopts.insert(ShortOpts::value_type(opt._shortname, it)).second)
|
||
|
throw mrw::invalid_argument(std::string(1, opt._shortname));
|
||
|
if (!_longopts.insert(LongOpts::value_type(opt._longname, it)).second)
|
||
|
throw mrw::invalid_argument(opt._longname);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
/** @brief setup the number of arguments
|
||
|
|
||
|
Setup the number of arguments.
|
||
|
This must be done before @c argv is shifted in.
|
||
|
|
||
|
Example:
|
||
|
|
||
|
@code
|
||
|
int main(int argv, const char * const * const argv) {
|
||
|
mrw::Args::instance()<<argc<<argv;
|
||
|
...
|
||
|
}
|
||
|
@endcode
|
||
|
*/
|
||
|
Args& operator<<(int argc) throw(mrw::bad_exception) {
|
||
|
_argc = argc;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
/** @brief setup the C array of command line arguments
|
||
|
|
||
|
Setup the C array of command line arguments. This must be the
|
||
|
very last thing shifted in.
|
||
|
|
||
|
Example:
|
||
|
|
||
|
@code
|
||
|
int main(int argv, const char * const * const argv) {
|
||
|
mrw::Args::instance()<<argc<<argv;
|
||
|
...
|
||
|
}
|
||
|
@endcode
|
||
|
*/
|
||
|
Args& operator<<(const char *const*const argv) throw(mrw::exception) {
|
||
|
if (_argc<0)
|
||
|
throw mrw::invalid_argument("argc was not set when shifting argv");
|
||
|
return parse(_argc, argv);
|
||
|
}
|
||
|
|
||
|
/** @brief add a description text
|
||
|
|
||
|
Add a description text. This description text is shown in the
|
||
|
@c DESCRIPTION section of the help display. If the description
|
||
|
text is shifted in more then once, the different sections are
|
||
|
appended with new line and an empty line between.
|
||
|
|
||
|
Example:
|
||
|
|
||
|
@code
|
||
|
mrw::Args::instance()<<"this is a description for --help";
|
||
|
@endcode
|
||
|
*/
|
||
|
Args& operator<<(const std::string& description) throw(mrw::exception) {
|
||
|
if (_description=="")
|
||
|
_description = description;
|
||
|
else
|
||
|
_description += "\n\n"+description;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
/** @brief set the help option
|
||
|
|
||
|
Define which option prints the help text. There is no code
|
||
|
needed for printing the help text: if the help option has been
|
||
|
shifted in, help is printed automatically at user request,
|
||
|
then the program is terminated. Only specify the short option
|
||
|
name, the long option name is known.
|
||
|
|
||
|
Example:
|
||
|
|
||
|
@code
|
||
|
mrw::Args::instance()<<'h';
|
||
|
@endcode
|
||
|
*/
|
||
|
Args& operator<<(char help) throw(mrw::exception) {
|
||
|
_help = help;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
/** @brief get an option, given the short option name
|
||
|
@throw mrw::out_of_range if the option does not exist
|
||
|
*/
|
||
|
const Opt& find(char c) const throw(mrw::exception) {
|
||
|
ShortOpts::const_iterator it(_shortopts.find(c));
|
||
|
if (it==_shortopts.end()) throw mrw::out_of_range(std::string(1, c));
|
||
|
return *it->second;
|
||
|
}
|
||
|
|
||
|
/** @brief get an option, given the long option name
|
||
|
@throw mrw::out_of_range if the option does not exist
|
||
|
*/
|
||
|
const Opt& find(const std::string& s) const throw(mrw::exception) {
|
||
|
LongOpts::const_iterator it(_longopts.find(s));
|
||
|
if (it==_longopts.end()) throw mrw::out_of_range(s);
|
||
|
return *it->second;
|
||
|
}
|
||
|
|
||
|
/** @brief get all non interpreted options
|
||
|
|
||
|
All user options that don't fit the defined and interpreted
|
||
|
options. The meaning for this is, that a user may append,
|
||
|
e.g. a list of file names.
|
||
|
*/
|
||
|
const OtherArgs& otherArgs() {
|
||
|
return _otherargs;
|
||
|
}
|
||
|
|
||
|
/** @brief get the file name of the executable, that's @c argv[0] */
|
||
|
const std::string& filename() throw(mrw::bad_exception) {
|
||
|
return _filename;
|
||
|
}
|
||
|
|
||
|
/** @brief print the help text, then exit */
|
||
|
void help() {
|
||
|
std::cout<<"USAGE: "<<std::endl
|
||
|
<<" "<<_filename<<" [ OPTIONS ]"<<std::endl
|
||
|
<<"OPTIONS:"<<std::endl;
|
||
|
for (Options::iterator it(_options.begin()); it!=_options.end(); ++it) {
|
||
|
std::cout<<" -"<<it->_shortname<<" | "<<it->_longname;
|
||
|
for (int i(0); i<it->_param.size(); ++i)
|
||
|
std::cout<<" <"<<(*it)[i]->typestr()<<">";
|
||
|
if (it->_param.size()>0) std::cout<<" (default: ";
|
||
|
for (int i(0); i<it->_param.size()-1; ++i)
|
||
|
std::cout<<(*it)[i]->printable()<<" ";
|
||
|
if (it->_param.size()>0)
|
||
|
std::cout<<(*it)[it->_param.size()-1]->printable()<<")";
|
||
|
std::cout<<std::endl<<" "<<it->help()<<std::endl;
|
||
|
}
|
||
|
if (_description.size()>0)
|
||
|
std::cout<<"DESCRIPTION:"<<std::endl
|
||
|
<<_description<<std::endl;
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
Args& parse(int argc, const char*const*const argv) throw(mrw::exception) {
|
||
|
if (argc>0) _filename = argv[0];
|
||
|
for (int i(1); i<argc; ++i) {
|
||
|
std::string arg(argv[i]);
|
||
|
if (arg.find("--")==0 && arg!="--") { // long arguments
|
||
|
LongOpts::iterator it(_longopts.find(arg));
|
||
|
if (it!=_longopts.end() || i+it->second->args().size()>=argc)
|
||
|
throw mrw::invalid_argument(arg);
|
||
|
it->second->set();
|
||
|
for (int j(0), l(it->second->args().size()); j<l; ++j) {
|
||
|
*(it->second->args().setable(j)) = argv[++i];
|
||
|
}
|
||
|
} else if (arg.find("-")==0) { // short arguments
|
||
|
// first check all, then set all
|
||
|
for (int j(1), l(arg.size()); j<l; ++j) {
|
||
|
ShortOpts::iterator it(_shortopts.find(arg[j]));
|
||
|
if (it==_shortopts.end() || it->second->args().size()>0 &&
|
||
|
(j+1!=l || i+it->second->args().size()>=argc))
|
||
|
throw mrw::invalid_argument(arg);
|
||
|
}
|
||
|
for (int j(1), l(arg.size()); j<l; ++j) {
|
||
|
ShortOpts::iterator it(_shortopts.find(arg[j]));
|
||
|
it->second->set();
|
||
|
if (j+1==l && it->second->args().size()>0) {
|
||
|
for (int k(0); k < it->second->args().size(); ++k) {
|
||
|
*(it->second->args().setable(k)) = argv[++i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if (arg!="--") _otherargs.push_back(arg);
|
||
|
while (++i<argc) _otherargs.push_back(argv[i]);
|
||
|
}
|
||
|
}
|
||
|
if (_help && find(_help)) help();
|
||
|
return *this;
|
||
|
}
|
||
|
typedef std::list<Opt> Options;
|
||
|
typedef std::map<char, Options::iterator> ShortOpts;
|
||
|
typedef std::map<std::string, Options::iterator> LongOpts;
|
||
|
Args(): _argc(-1), _help(0) {} // singleton
|
||
|
Args& operator=(const Args&); // singleton, not implemented
|
||
|
std::string _filename;
|
||
|
Options _options;
|
||
|
ShortOpts _shortopts;
|
||
|
LongOpts _longopts;
|
||
|
OtherArgs _otherargs;
|
||
|
int _argc;
|
||
|
char _help;
|
||
|
std::string _description;
|
||
|
};
|
||
|
|
||
|
//@}
|
||
|
}
|