|
|
@ -7,6 +7,8 @@ |
|
|
|
#ifndef __ARGS__ |
|
|
|
#ifndef __ARGS__ |
|
|
|
#define __ARGS__ |
|
|
|
#define __ARGS__ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <mrw/iomanip> |
|
|
|
|
|
|
|
|
|
|
|
#include <vector> |
|
|
|
#include <vector> |
|
|
|
#include <map> |
|
|
|
#include <map> |
|
|
|
#include <memory> |
|
|
|
#include <memory> |
|
|
@ -15,10 +17,11 @@ |
|
|
|
#include <sstream> |
|
|
|
#include <sstream> |
|
|
|
#include <stdexcept> |
|
|
|
#include <stdexcept> |
|
|
|
#include <numeric> |
|
|
|
#include <numeric> |
|
|
|
#include <cstdlib> |
|
|
|
#include <cstdlib> // exit() |
|
|
|
|
|
|
|
|
|
|
|
// check if code is compiled with a new C++11 compiler |
|
|
|
// check if code is compiled with a new C++11 compiler |
|
|
|
// otherwise there is a fallback wich makes everything much more compliacted |
|
|
|
// otherwise there is a fallback wich makes everything much more compliacted |
|
|
|
|
|
|
|
#ifndef ARGS__OLD_PRE11_COMPILER |
|
|
|
#if __cplusplus < 201103L |
|
|
|
#if __cplusplus < 201103L |
|
|
|
/// Code is compiled with an old non C++11 standard compliant compiler |
|
|
|
/// Code is compiled with an old non C++11 standard compliant compiler |
|
|
|
/** There are workarounds for old non C++11 compatible |
|
|
|
/** There are workarounds for old non C++11 compatible |
|
|
@ -33,6 +36,13 @@ |
|
|
|
#warning this is deprecated and will be removed in future releases |
|
|
|
#warning this is deprecated and will be removed in future releases |
|
|
|
#warning refere to the library documentation for more details |
|
|
|
#warning refere to the library documentation for more details |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @page oldcompiler Workaround for old non C++11 compilers |
|
|
|
|
|
|
|
... to be documented |
|
|
|
|
|
|
|
@note Old compilers are automatically detected and the flag |
|
|
|
|
|
|
|
@refs ARGS__OLD_PRE11_COMPILER is set. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
#ifdef ARGS__OLD_PRE11_COMPILER |
|
|
|
#ifdef ARGS__OLD_PRE11_COMPILER |
|
|
|
#include <boost/shared_ptr.hpp> |
|
|
|
#include <boost/shared_ptr.hpp> |
|
|
@ -46,12 +56,7 @@ namespace std { |
|
|
|
}; |
|
|
|
}; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/** @page oldcompiler Workaround for old non C++11 compilers |
|
|
|
namespace mrw { |
|
|
|
... to be documented |
|
|
|
|
|
|
|
@note Old compilers are automatically detected and the flag |
|
|
|
|
|
|
|
@refs ARGS__OLD_PRE11_COMPILER is set. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Cool and easy evaluation of commandline arguments in C++11. |
|
|
|
/// Cool and easy evaluation of commandline arguments in C++11. |
|
|
|
/** Evaluating command line arguments is extremely easy with this library: |
|
|
|
/** Evaluating command line arguments is extremely easy with this library: |
|
|
|
@begincode |
|
|
|
@begincode |
|
|
@ -66,14 +71,17 @@ namespace std { |
|
|
|
int x(0), y(0); // bound to option --coord |
|
|
|
int x(0), y(0); // bound to option --coord |
|
|
|
|
|
|
|
|
|
|
|
// bind and evaluate options |
|
|
|
// bind and evaluate options |
|
|
|
args::init(argc, argv, "This is an example for argument processing.", { |
|
|
|
args::parse(argc, argv, "This is an example for argument processing.", |
|
|
|
|
|
|
|
{ |
|
|
|
{"h", "help", "show this help", {args::help(), args::exit()}}, |
|
|
|
{"h", "help", "show this help", {args::help(), args::exit()}}, |
|
|
|
{"r", "repeat", "number of repetitions", {args::param(r, "number")}}, |
|
|
|
{"r", "repeat", "number of repetitions", |
|
|
|
|
|
|
|
{args::param(r, "number")}}, |
|
|
|
{"f", "flag", "check a flag", {args::param(flag)}}, |
|
|
|
{"f", "flag", "check a flag", {args::param(flag)}}, |
|
|
|
{"t", "text", "pass a text", {args::param(txt, "text")}}, |
|
|
|
{"t", "text", "pass a text", {args::param(txt, "text")}}, |
|
|
|
{"c", "coord", "add some 2D coordinates", {args::param(x, "x"), |
|
|
|
{"c", "coord", "add some 2D coordinates", {args::param(x, "x"), |
|
|
|
args::param(y, "y")}}, |
|
|
|
args::param(y, "y")}}, |
|
|
|
{"", "test", "call test_func, no shortcut", {args::func(test_func)}}, |
|
|
|
{"", "test", "call test_func, no shortcut", |
|
|
|
|
|
|
|
{args::func(test_func)}}, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// [...] now the variables are setup according to the user's choice |
|
|
|
// [...] now the variables are setup according to the user's choice |
|
|
@ -90,8 +98,7 @@ namespace std { |
|
|
|
non C++11 compliant compilers, so the use of a modern |
|
|
|
non C++11 compliant compilers, so the use of a modern |
|
|
|
compiler is strongly recommended. On GNU GCC, you may have |
|
|
|
compiler is strongly recommended. On GNU GCC, you may have |
|
|
|
to add the commandline option @c -std=c++11 |
|
|
|
to add the commandline option @c -std=c++11 |
|
|
|
@note I suggest to take this library into the next C++ standard. |
|
|
|
@note I suggest to take this library into the next C++ standard. */ |
|
|
|
*/ |
|
|
|
|
|
|
|
namespace args { |
|
|
|
namespace args { |
|
|
|
/// Parent for holding a reference to a parameter variable. |
|
|
|
/// Parent for holding a reference to a parameter variable. |
|
|
|
/** This class ist used only as parent for instances of template |
|
|
|
/** This class ist used only as parent for instances of template |
|
|
@ -143,7 +150,9 @@ namespace args { |
|
|
|
// special case: boolean has no parameter |
|
|
|
// special case: boolean has no parameter |
|
|
|
template<> class parameter<bool>: public abstract_parameter { |
|
|
|
template<> class parameter<bool>: public abstract_parameter { |
|
|
|
public: |
|
|
|
public: |
|
|
|
parameter(bool& ref, const std::string& = std::string()): _ref(ref=false) {} |
|
|
|
parameter(bool& ref, const std::string& = std::string()): |
|
|
|
|
|
|
|
_ref(ref=false) { |
|
|
|
|
|
|
|
} |
|
|
|
virtual void evaluate(char**&, char**) { |
|
|
|
virtual void evaluate(char**&, char**) { |
|
|
|
_ref = true; |
|
|
|
_ref = true; |
|
|
|
} |
|
|
|
} |
|
|
@ -151,9 +160,11 @@ namespace args { |
|
|
|
bool& _ref; |
|
|
|
bool& _ref; |
|
|
|
}; |
|
|
|
}; |
|
|
|
// special case: string cannot easily be shifted |
|
|
|
// special case: string cannot easily be shifted |
|
|
|
template<typename T> class parameter<std::basic_string<T> >: public abstract_parameter { |
|
|
|
template<typename T> class parameter<std::basic_string<T> >: |
|
|
|
|
|
|
|
public abstract_parameter { |
|
|
|
public: |
|
|
|
public: |
|
|
|
parameter(std::basic_string<T>& ref, const std::string& s = std::string()): |
|
|
|
parameter(std::basic_string<T>& ref, |
|
|
|
|
|
|
|
const std::string& s = std::string()): |
|
|
|
_ref(ref), _type(s) {} |
|
|
|
_ref(ref), _type(s) {} |
|
|
|
virtual void evaluate(char**& a, char** max) { |
|
|
|
virtual void evaluate(char**& a, char** max) { |
|
|
|
if (max<a+1) |
|
|
|
if (max<a+1) |
|
|
@ -178,7 +189,9 @@ namespace args { |
|
|
|
// special case: if a function is called |
|
|
|
// special case: if a function is called |
|
|
|
template<> class parameter<void(*)()>: public abstract_parameter { |
|
|
|
template<> class parameter<void(*)()>: public abstract_parameter { |
|
|
|
public: |
|
|
|
public: |
|
|
|
parameter(void(*ref)(), const std::string& = std::string()): _ref(ref) {} |
|
|
|
parameter(void(*ref)(), const std::string& = std::string()): |
|
|
|
|
|
|
|
_ref(ref) { |
|
|
|
|
|
|
|
} |
|
|
|
virtual void evaluate(char**&, char**) { |
|
|
|
virtual void evaluate(char**&, char**) { |
|
|
|
_ref(); |
|
|
|
_ref(); |
|
|
|
} |
|
|
|
} |
|
|
@ -191,7 +204,7 @@ namespace args { |
|
|
|
return std::shared_ptr<abstract_parameter>(new args::parameter<T>(t, s)); |
|
|
|
return std::shared_ptr<abstract_parameter>(new args::parameter<T>(t, s)); |
|
|
|
} |
|
|
|
} |
|
|
|
struct declaration { |
|
|
|
struct declaration { |
|
|
|
#ifndef ARGS__CPLUSPLUS11 |
|
|
|
#ifdef ARGS__OLD_PRE11_COMPILER |
|
|
|
declaration(std::string p1, std::string p2, std::string p3, |
|
|
|
declaration(std::string p1, std::string p2, std::string p3, |
|
|
|
std::vector<std::shared_ptr<abstract_parameter> > p4): |
|
|
|
std::vector<std::shared_ptr<abstract_parameter> > p4): |
|
|
|
short_arg(p1), long_arg(p2), desc(p3), params(p4) { |
|
|
|
short_arg(p1), long_arg(p2), desc(p3), params(p4) { |
|
|
@ -215,22 +228,21 @@ namespace args { |
|
|
|
return a; |
|
|
|
return a; |
|
|
|
} |
|
|
|
} |
|
|
|
void match(const std::string& arg, char**& a, char** max) { |
|
|
|
void match(const std::string& arg, char**& a, char** max) { |
|
|
|
#ifndef ARGS__CPLUSPLUS11 |
|
|
|
#ifdef ARGS__OLD_PRE11_COMPILER |
|
|
|
arg_map::iterator it(args().find(arg)); |
|
|
|
arg_map::iterator it(args().find(arg)); |
|
|
|
#else |
|
|
|
#else |
|
|
|
auto it(args().find(arg)); |
|
|
|
auto it(args().find(arg)); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
if (it==args().end()) |
|
|
|
if (it==args().end()) |
|
|
|
throw std::runtime_error("unknown argument: "+std::string(*a)); |
|
|
|
throw std::runtime_error("unknown argument: "+std::string(*a)); |
|
|
|
#ifndef ARGS__CPLUSPLUS11 |
|
|
|
#ifdef ARGS__OLD_PRE11_COMPILER |
|
|
|
for (std::vector<std::shared_ptr<abstract_parameter> >::iterator |
|
|
|
for (std::vector<std::shared_ptr<abstract_parameter> >::iterator |
|
|
|
it2(it->second.begin()); it2!=it->second.end(); ++it2) { |
|
|
|
it2(it->second.begin()); it2!=it->second.end(); ++it2) |
|
|
|
#else |
|
|
|
#else |
|
|
|
for (auto it2(it->second.begin()); it2!=it->second.end(); ++it2) { |
|
|
|
for (auto it2(it->second.begin()); it2!=it->second.end(); ++it2) |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
(*it2)->evaluate(a, max); |
|
|
|
(*it2)->evaluate(a, max); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// Filename as passed in argv[0]. |
|
|
|
/// Filename as passed in argv[0]. |
|
|
|
/** Used in the help display. |
|
|
|
/** Used in the help display. |
|
|
|
@note This function emulates a global variable using parts of a |
|
|
|
@note This function emulates a global variable using parts of a |
|
|
@ -263,30 +275,32 @@ namespace args { |
|
|
|
used in @ref show_help |
|
|
|
used in @ref show_help |
|
|
|
@param l list of options and parameters to be parsed |
|
|
|
@param l list of options and parameters to be parsed |
|
|
|
@raram ret documentation of the return values of the program */ |
|
|
|
@raram ret documentation of the return values of the program */ |
|
|
|
static void init(int argc, char** argv, const std::string& desc, list l, |
|
|
|
static void parse(int argc, char** argv, const std::string& desc, list l, |
|
|
|
const std::string& ret = std::string()) { |
|
|
|
const std::string& ret = std::string()) { |
|
|
|
filename(argv[0]); // store filename for later use in help |
|
|
|
filename(argv[0]); // store filename for later use in help |
|
|
|
description(desc); // store program description for later use in help |
|
|
|
description(desc); // store program description for later use in help |
|
|
|
returns(ret); // store return values description for later use in help |
|
|
|
returns(ret); // store return documentation for later use in help |
|
|
|
arg_list() = l; // store options and parameters for later use in help |
|
|
|
arg_list() = l; // store options and parameters for later use in help |
|
|
|
// setup the argument mapping table |
|
|
|
// setup the argument mapping table |
|
|
|
#ifndef ARGS__CPLUSPLUS11 |
|
|
|
#ifdef ARGS__OLD_PRE11_COMPILER |
|
|
|
for (list::iterator it(l.begin()); it!=l.end(); ++it) { |
|
|
|
for (list::iterator it(l.begin()); it!=l.end(); ++it) |
|
|
|
#else |
|
|
|
#else |
|
|
|
for (auto it(l.begin()); it!=l.end(); ++it) { |
|
|
|
for (auto it(l.begin()); it!=l.end(); ++it) |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
{ |
|
|
|
if (it->short_arg.size()==1) args()[it->short_arg] = it->params; |
|
|
|
if (it->short_arg.size()==1) args()[it->short_arg] = it->params; |
|
|
|
if (it->long_arg.size()) args()["--"+it->long_arg] = it->params; |
|
|
|
if (it->long_arg.size()) args()["--"+it->long_arg] = it->params; |
|
|
|
} |
|
|
|
} |
|
|
|
// parse commandline and evaluate the arguments |
|
|
|
// parse commandline and evaluate the arguments |
|
|
|
#ifndef ARGS__CPLUSPLUS11 |
|
|
|
#ifdef ARGS__OLD_PRE11_COMPILER |
|
|
|
for (char** a(argv+1); a<argv+argc; ++a) { |
|
|
|
for (char** a(argv+1); a<argv+argc; ++a) |
|
|
|
#else |
|
|
|
#else |
|
|
|
for (auto a(argv+1); a<argv+argc; ++a) { |
|
|
|
for (auto a(argv+1); a<argv+argc; ++a) |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
{ |
|
|
|
std::string arg(*a); |
|
|
|
std::string arg(*a); |
|
|
|
if (arg.size()>1&&arg[0]=='-'&&arg[1]!='-') { // short argument |
|
|
|
if (arg.size()>1&&arg[0]=='-'&&arg[1]!='-') { // short argument |
|
|
|
#ifndef ARGS__CPLUSPLUS11 |
|
|
|
#ifdef ARGS__OLD_PRE11_COMPILER |
|
|
|
for (std::string::iterator it(arg.begin()+1); it!=arg.end(); ++it) |
|
|
|
for (std::string::iterator it(arg.begin()+1); it!=arg.end(); ++it) |
|
|
|
#else |
|
|
|
#else |
|
|
|
for (auto it(arg.begin()+1); it!=arg.end(); ++it) |
|
|
|
for (auto it(arg.begin()+1); it!=arg.end(); ++it) |
|
|
@ -297,72 +311,6 @@ namespace args { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
//! IO-Manipulator to split long lines into several shorter lines. |
|
|
|
|
|
|
|
template <class _CharT = char, class _Traits = std::char_traits<_CharT> > |
|
|
|
|
|
|
|
class basic_split /*: public std::basic_ostream<_CharT, _Traits>*/ { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
basic_split(int width=80, int indent=0, char fill=' '): |
|
|
|
|
|
|
|
_width(width), _indent(indent), _fill(fill), _os(0) { |
|
|
|
|
|
|
|
if (_width<_indent) |
|
|
|
|
|
|
|
#ifndef ARGS__CPLUSPLUS11 |
|
|
|
|
|
|
|
throw std::runtime_error(((std::stringstream&) |
|
|
|
|
|
|
|
(std::stringstream() |
|
|
|
|
|
|
|
<<"wrong use of split: width is "<<_width |
|
|
|
|
|
|
|
<<" but should be larger than indent," |
|
|
|
|
|
|
|
<<" which is "<<_indent)).str()); |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
throw std::runtime_error("wrong use of split: width is "+ |
|
|
|
|
|
|
|
std::to_string(_width)+ |
|
|
|
|
|
|
|
" but should be larger than indent," |
|
|
|
|
|
|
|
" which is "+std::to_string(_indent)); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
virtual ~basic_split() { |
|
|
|
|
|
|
|
flush(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
friend basic_split& operator<<(std::basic_ostream<_CharT, _Traits>& os, |
|
|
|
|
|
|
|
const basic_split& s) { |
|
|
|
|
|
|
|
if (s._os!=&os) { |
|
|
|
|
|
|
|
const_cast<basic_split&>(s).flush(); |
|
|
|
|
|
|
|
const_cast<basic_split&>(s)._os = &os; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return const_cast<basic_split&>(s); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
template <typename T> basic_split& operator<<(T t) { |
|
|
|
|
|
|
|
if (!_os) |
|
|
|
|
|
|
|
throw std::runtime_error("wrong use of split, it is an io manipulator" |
|
|
|
|
|
|
|
" and must be used within a stream"); |
|
|
|
|
|
|
|
_buffer<<t; |
|
|
|
|
|
|
|
while (_buffer.str().size()>=_width-_indent) { |
|
|
|
|
|
|
|
if (_indent) *_os<<std::setw(_indent)<<std::setfill(_fill)<<_fill; |
|
|
|
|
|
|
|
std::string::size_type pos |
|
|
|
|
|
|
|
(_buffer.str().find_last_of(' ', _width-_indent)); |
|
|
|
|
|
|
|
std::string::size_type next(pos+1); |
|
|
|
|
|
|
|
if (pos==std::string::npos) { |
|
|
|
|
|
|
|
pos=_width-_indent; |
|
|
|
|
|
|
|
next=pos; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
*_os<<_buffer.str().substr(0, pos)<<std::endl; |
|
|
|
|
|
|
|
_buffer.str(_buffer.str().substr(next)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return *this; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
void flush() { |
|
|
|
|
|
|
|
if (_os) { |
|
|
|
|
|
|
|
if (_indent) *_os<<std::setw(_indent)<<std::setfill(_fill)<<_fill; |
|
|
|
|
|
|
|
*_os<<_buffer.str(); |
|
|
|
|
|
|
|
_buffer.clear(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
int _width; |
|
|
|
|
|
|
|
int _indent; |
|
|
|
|
|
|
|
char _fill; |
|
|
|
|
|
|
|
std::stringstream _buffer; |
|
|
|
|
|
|
|
std::basic_ostream<_CharT, _Traits>* _os; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
typedef basic_split<char> split; |
|
|
|
|
|
|
|
void show_help(const std::string& synopsis_txt="SYNOPSIS", |
|
|
|
void show_help(const std::string& synopsis_txt="SYNOPSIS", |
|
|
|
const std::string& description_txt="DESCRIPTION", |
|
|
|
const std::string& description_txt="DESCRIPTION", |
|
|
|
const std::string& options_txt="OPTIONS", |
|
|
|
const std::string& options_txt="OPTIONS", |
|
|
@ -375,15 +323,16 @@ namespace args { |
|
|
|
<<split(max_line, indent)<<description(); //! @bug |
|
|
|
<<split(max_line, indent)<<description(); //! @bug |
|
|
|
std::cout<<std::endl<<std::endl |
|
|
|
std::cout<<std::endl<<std::endl |
|
|
|
<<options_txt<<std::endl; |
|
|
|
<<options_txt<<std::endl; |
|
|
|
#ifndef ARGS__CPLUSPLUS11 |
|
|
|
#ifdef ARGS__OLD_PRE11_COMPILER |
|
|
|
for (list::iterator arg(arg_list().begin()); arg!=arg_list().end(); ++arg) { |
|
|
|
for (list::iterator arg(arg_list().begin()); arg!=arg_list().end(); ++arg) |
|
|
|
#else |
|
|
|
#else |
|
|
|
for (auto arg(arg_list().begin()); arg!=arg_list().end(); ++arg) { |
|
|
|
for (auto arg(arg_list().begin()); arg!=arg_list().end(); ++arg) |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
{ |
|
|
|
std::string o((arg->short_arg.size()?"-"+arg->short_arg:"")+ |
|
|
|
std::string o((arg->short_arg.size()?"-"+arg->short_arg:"")+ |
|
|
|
(arg->short_arg.size()&&arg->long_arg.size()?", ":"")+ |
|
|
|
(arg->short_arg.size()&&arg->long_arg.size()?", ":"")+ |
|
|
|
(arg->long_arg.size()?"--"+arg->long_arg:"")); |
|
|
|
(arg->long_arg.size()?"--"+arg->long_arg:"")); |
|
|
|
#ifndef ARGS__CPLUSPLUS11 |
|
|
|
#ifdef ARGS__OLD_PRE11_COMPILER |
|
|
|
std::string a; |
|
|
|
std::string a; |
|
|
|
for (std::vector<std::shared_ptr<abstract_parameter> >::iterator |
|
|
|
for (std::vector<std::shared_ptr<abstract_parameter> >::iterator |
|
|
|
p(arg->params.begin()); |
|
|
|
p(arg->params.begin()); |
|
|
@ -435,4 +384,5 @@ namespace args { |
|
|
|
return func(args::do_exit); |
|
|
|
return func(args::do_exit); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|