diff --git a/doc/examples/arguments.cxx b/doc/examples/arguments.cxx index 653bfd6..898dc32 100644 --- a/doc/examples/arguments.cxx +++ b/doc/examples/arguments.cxx @@ -21,57 +21,66 @@ int main(int argc, char** argv) try { // bind and evaluate options #ifdef ARGS__OLD_PRE11_COMPILER - args::list options; - std::vector > params; - params.push_back(args::help()); - params.push_back(args::exit()); - options.push_back(args::declaration("h", "help", "show this help", params)); + mrw::args::list options; + std::vector > params; + params.push_back(mrw::args::help()); + params.push_back(mrw::args::exit()); + options.push_back(mrw::args::declaration("h", "help", "show this help", + params)); params.clear(); - params.push_back(args::param(r, "number")); - options.push_back(args::declaration("r", "repeat", "number of repetitions", - params)); + params.push_back(mrw::args::param(r, "number")); + options.push_back(mrw::args::declaration("r", "repeat", + "number of repetitions", + params)); params.clear(); - params.push_back(args::param(flag)); - options.push_back(args::declaration("f", "flag", "check a flag", params)); + params.push_back(mrw::args::param(flag)); + options.push_back(mrw::args::declaration("f", "flag", "check a flag", + params)); params.clear(); - params.push_back(args::param(txt, "text")); - options.push_back(args::declaration("t", "text", "pass a text", params)); + params.push_back(mrw::args::param(txt, "text")); + options.push_back(mrw::args::declaration("t", "text", "pass a text", params)); params.clear(); - params.push_back(args::param(x, "x")); - params.push_back(args::param(y, "y")); - options.push_back(args::declaration("c", "coord", "add some 2D coordinates", - params)); + params.push_back(mrw::args::param(x, "x")); + params.push_back(mrw::args::param(y, "y")); + options.push_back(mrw::args::declaration("c", "coord", + "add some 2D coordinates", + params)); params.clear(); - params.push_back(args::func(test_func)); - options.push_back(args::declaration("", "test", - "call test_func, no shortcut", params)); - args::init(argc, argv, "This is an example for argument processing.", - options); + params.push_back(mrw::args::func(test_func)); + options.push_back(mrw::args::declaration("", "test", + "call test_func, no shortcut", + params)); + mrw::args::parse(argc, argv, "This is an example for argument processing.", + options); #else - args::init(argc, argv, - "This is an example for argument processing. If the description " - "is very long, it is automatically splitted over several lines " - "and indented on each new line. Arguments may have several " - "parameters. Help is generated automatically from the argument " - "declaration. The argument declaration contains long and short " - "options and a list of parameters.", - { - {"h", "help", "show this help", {args::help(), args::exit()}}, - {"r", "repeat", "number of repetitions", - {args::param(r, "number")}}, - {"f", "flag", - "check a flag; this is a boolean, so it is false by " - "default and true if the user specifies the flag on " - "the command line", {args::param(flag)}}, - {"t", "text", "pass a text", {args::param(txt, "text")}}, - {"c", "coord", - "add some 2D coordinates; this is an example on how " - "you can add more than one parameter", - {args::param(x, "x"), args::param(y, "y")}}, - {"", "test", "call test_func, no shortcut", - {args::func(test_func)}}, - }, - "Returns a status of 0 on success and 1 on any error."); + mrw::args::parse(argc, argv, + "This is an example for argument processing. If the" + " description is very long, it is automatically splitted" + " over several lines and indented on each new line." + " Arguments may have several parameters. Help is" + " generated automatically from the argument declaration." + " The argument declaration contains long and short options" + " and a list of parameters.", + { + {"h", "help", "show this help", + {mrw::args::help(), mrw::args::exit()}}, + {"r", "repeat", "number of repetitions", + {mrw::args::param(r, "number")}}, + {"f", "flag", + "check a flag; this is a boolean, so it is false by " + "default and true if the user specifies the flag on " + "the command line", {mrw::args::param(flag)}}, + {"t", "text", "pass a text", + {mrw::args::param(txt, "text")}}, + {"c", "coord", + "add some 2D coordinates; this is an example on how " + "you can add more than one parameter", + {mrw::args::param(x, "x"), + mrw::args::param(y, "y")}}, + {"", "test", "call test_func, no shortcut", + {mrw::args::func(test_func)}}, + }, + "Returns a status of 0 on success and 1 on any error."); #endif // show the result diff --git a/src/mrw/args b/src/mrw/args index b71c618..0c35d9c 100644 --- a/src/mrw/args +++ b/src/mrw/args @@ -7,6 +7,8 @@ #ifndef __ARGS__ #define __ARGS__ +#include + #include #include #include @@ -15,10 +17,11 @@ #include #include #include -#include +#include // exit() // check if code is compiled with a new C++11 compiler // otherwise there is a fallback wich makes everything much more compliacted +#ifndef ARGS__OLD_PRE11_COMPILER #if __cplusplus < 201103L /// Code is compiled with an old non C++11 standard compliant compiler /** 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 refere to the library documentation for more details #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 #include @@ -46,393 +56,333 @@ namespace std { }; #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. - */ - -/// Cool and easy evaluation of commandline arguments in C++11. -/** Evaluating command line arguments is extremely easy with this library: - @begincode - void test_func(); // bound to option --test - - int main(int argc, char** argv) try { - - // option variables - bool flag; // bound to option --flag - int r(5); // bound to option --repeat - std::string txt("Hello World"); // bound to option --text - int x(0), y(0); // bound to option --coord +namespace mrw { + /// Cool and easy evaluation of commandline arguments in C++11. + /** Evaluating command line arguments is extremely easy with this library: + @begincode + void test_func(); // bound to option --test + + int main(int argc, char** argv) try { + + // option variables + bool flag; // bound to option --flag + int r(5); // bound to option --repeat + std::string txt("Hello World"); // bound to option --text + int x(0), y(0); // bound to option --coord - // bind and evaluate options - args::init(argc, argv, "This is an example for argument processing.", { - {"h", "help", "show this help", {args::help(), args::exit()}}, - {"r", "repeat", "number of repetitions", {args::param(r, "number")}}, - {"f", "flag", "check a flag", {args::param(flag)}}, - {"t", "text", "pass a text", {args::param(txt, "text")}}, - {"c", "coord", "add some 2D coordinates", {args::param(x, "x"), - args::param(y, "y")}}, - {"", "test", "call test_func, no shortcut", {args::func(test_func)}}, - }); + // bind and evaluate options + args::parse(argc, argv, "This is an example for argument processing.", + { + {"h", "help", "show this help", {args::help(), args::exit()}}, + {"r", "repeat", "number of repetitions", + {args::param(r, "number")}}, + {"f", "flag", "check a flag", {args::param(flag)}}, + {"t", "text", "pass a text", {args::param(txt, "text")}}, + {"c", "coord", "add some 2D coordinates", {args::param(x, "x"), + args::param(y, "y")}}, + {"", "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 - return 0; - } catch (const std::exception& x) { // error in commandline options - std::cerr<<"**** ERROR: "< class parameter: public abstract_parameter { + public: + parameter(T& ref, const std::string& s = std::string()): + _ref(ref), _type(s) {} + virtual void evaluate(char**& a, char** max) { + if (max>_ref; + } + virtual operator std::string() { + std::stringstream ss; + ss<<_ref; + return ss.str(); + } + virtual std::string type() { + return _type.size()?" <"+_type+">":""; + } + private: + T& _ref; + std::string _type; + }; + // special case: boolean has no parameter + template<> class parameter: public abstract_parameter { + public: + parameter(bool& ref, const std::string& = std::string()): + _ref(ref=false) { + } + virtual void evaluate(char**&, char**) { + _ref = true; + } + private: + bool& _ref; + }; + // special case: string cannot easily be shifted + template class parameter >: + public abstract_parameter { + public: + parameter(std::basic_string& ref, + const std::string& s = std::string()): + _ref(ref), _type(s) {} + virtual void evaluate(char**& a, char** max) { + if (max(std::istreambuf_iterator(ss), + std::istreambuf_iterator()); + } + virtual operator std::string() { + std::stringstream ss; + ss<<_ref; + return ss.str(); + } + virtual std::string type() { + return _type.size()?" <"+_type+">":""; + } + private: + std::basic_string& _ref; + std::string _type; + }; + // special case: if a function is called + template<> class parameter: public abstract_parameter { + public: + parameter(void(*ref)(), const std::string& = std::string()): + _ref(ref) { + } + virtual void evaluate(char**&, char**) { + _ref(); + } + private: + void(*_ref)(); + }; + template + std::shared_ptr param + (T& t, const std::string& s = std::string()) { + return std::shared_ptr(new args::parameter(t, s)); } - @endcode - @note This library requires C++11, but there is also a fallback - for old compilers. But the calling syntax is much worse on - non C++11 compliant compilers, so the use of a modern - compiler is strongly recommended. On GNU GCC, you may have - to add the commandline option @c -std=c++11 - @note I suggest to take this library into the next C++ standard. - */ -namespace args { - /// Parent for holding a reference to a parameter variable. - /** This class ist used only as parent for instances of template - parameters. It represents one parameter that is evaluated when - a commandline option is given. The derived classes hold a - reference to a variable that is set in method @ref evaluate when - the specific commandline parameter is given. */ - class abstract_parameter { - public: - /// Called when the user specifies the related commandline option. - /** Method must be implemented according to the specific type in - the child classes. */ - virtual void evaluate(char**& a, char** max) = 0; - /// Convert the actual value to a string. - /** Defaults to empty string, can be overwritten in child - classes. Used by the help function to show the default - value. */ - virtual operator std::string() { - return std::string(); - } - virtual std::string type() { - return std::string(); - } - }; - // default implementation for all types - template class parameter: public abstract_parameter { - public: - parameter(T& ref, const std::string& s = std::string()): - _ref(ref), _type(s) {} - virtual void evaluate(char**& a, char** max) { - if (max>_ref; - } - virtual operator std::string() { - std::stringstream ss; - ss<<_ref; - return ss.str(); - } - virtual std::string type() { - return _type.size()?" <"+_type+">":""; - } - private: - T& _ref; - std::string _type; - }; - // special case: boolean has no parameter - template<> class parameter: public abstract_parameter { - public: - parameter(bool& ref, const std::string& = std::string()): _ref(ref=false) {} - virtual void evaluate(char**&, char**) { - _ref = true; - } - private: - bool& _ref; - }; - // special case: string cannot easily be shifted - template class parameter >: public abstract_parameter { - public: - parameter(std::basic_string& ref, const std::string& s = std::string()): - _ref(ref), _type(s) {} - virtual void evaluate(char**& a, char** max) { - if (max(std::istreambuf_iterator(ss), - std::istreambuf_iterator()); - } - virtual operator std::string() { - std::stringstream ss; - ss<<_ref; - return ss.str(); - } - virtual std::string type() { - return _type.size()?" <"+_type+">":""; - } - private: - std::basic_string& _ref; - std::string _type; - }; - // special case: if a function is called - template<> class parameter: public abstract_parameter { - public: - parameter(void(*ref)(), const std::string& = std::string()): _ref(ref) {} - virtual void evaluate(char**&, char**) { - _ref(); - } - private: - void(*_ref)(); - }; - template - std::shared_ptr param - (T& t, const std::string& s = std::string()) { - return std::shared_ptr(new args::parameter(t, s)); - } - struct declaration { -#ifndef ARGS__CPLUSPLUS11 - declaration(std::string p1, std::string p2, std::string p3, - std::vector > p4): - short_arg(p1), long_arg(p2), desc(p3), params(p4) { - } + struct declaration { +#ifdef ARGS__OLD_PRE11_COMPILER + declaration(std::string p1, std::string p2, std::string p3, + std::vector > p4): + short_arg(p1), long_arg(p2), desc(p3), params(p4) { + } #endif - std::string short_arg; - std::string long_arg; - std::string desc; - std::vector > params; - }; - typedef std::map > > - arg_map; - static arg_map& args() { - static arg_map a; - return a; - } - typedef std::vector list; - static list& arg_list() { - static list a; - return a; - } - void match(const std::string& arg, char**& a, char** max) { -#ifndef ARGS__CPLUSPLUS11 - arg_map::iterator it(args().find(arg)); + std::string short_arg; + std::string long_arg; + std::string desc; + std::vector > params; + }; + typedef std::map > > + arg_map; + static arg_map& args() { + static arg_map a; + return a; + } + typedef std::vector list; + static list& arg_list() { + static list a; + return a; + } + void match(const std::string& arg, char**& a, char** max) { +#ifdef ARGS__OLD_PRE11_COMPILER + arg_map::iterator it(args().find(arg)); #else - auto it(args().find(arg)); + auto it(args().find(arg)); #endif - if (it==args().end()) - throw std::runtime_error("unknown argument: "+std::string(*a)); -#ifndef ARGS__CPLUSPLUS11 - for (std::vector >::iterator - it2(it->second.begin()); it2!=it->second.end(); ++it2) { + if (it==args().end()) + throw std::runtime_error("unknown argument: "+std::string(*a)); +#ifdef ARGS__OLD_PRE11_COMPILER + for (std::vector >::iterator + it2(it->second.begin()); it2!=it->second.end(); ++it2) #else - for (auto it2(it->second.begin()); it2!=it->second.end(); ++it2) { + for (auto it2(it->second.begin()); it2!=it->second.end(); ++it2) #endif - (*it2)->evaluate(a, max); + (*it2)->evaluate(a, max); } - } - /// Filename as passed in argv[0]. - /** Used in the help display. - @note This function emulates a global variable using parts of a - singleton pattern. */ - static std::string filename(const std::string& arg0 = std::string()) { - static std::string file(arg0); - return file; - } - /// Description of the program. - /** Used in the help display. - @note This function emulates a global variable using parts of a - singleton pattern. */ - static std::string description(const std::string& desc = std::string()) { - static std::string d(desc); - return d; - } - /// Return values of the program. - /** Used in the help display. - @note This function emulates a global variable using parts of a - singleton pattern. */ - static std::string returns(const std::string& ret = std::string()) { - static std::string r(ret); - return r; - } - /// Initialize all parameters according to the commandline options. - /** Sets up the parser from the @ref list of parameters - @param argc the argument count as given in C++ @c main function - @param argv the array of arguments as given in C++ @c main function - @param descr a string describing what the program does, - used in @ref show_help - @param l list of options and parameters to be parsed - @raram ret documentation of the return values of the program */ - static void init(int argc, char** argv, const std::string& desc, list l, - const std::string& ret = std::string()) { - filename(argv[0]); // store filename 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 - arg_list() = l; // store options and parameters for later use in help - // setup the argument mapping table -#ifndef ARGS__CPLUSPLUS11 - for (list::iterator it(l.begin()); it!=l.end(); ++it) { -#else - for (auto it(l.begin()); it!=l.end(); ++it) { -#endif - if (it->short_arg.size()==1) args()[it->short_arg] = it->params; - if (it->long_arg.size()) args()["--"+it->long_arg] = it->params; + /// Filename as passed in argv[0]. + /** Used in the help display. + @note This function emulates a global variable using parts of a + singleton pattern. */ + static std::string filename(const std::string& arg0 = std::string()) { + static std::string file(arg0); + return file; + } + /// Description of the program. + /** Used in the help display. + @note This function emulates a global variable using parts of a + singleton pattern. */ + static std::string description(const std::string& desc = std::string()) { + static std::string d(desc); + return d; } - // parse commandline and evaluate the arguments -#ifndef ARGS__CPLUSPLUS11 - for (char** a(argv+1); a1&&arg[0]=='-'&&arg[1]!='-') { // short argument -#ifndef ARGS__CPLUSPLUS11 - for (std::string::iterator it(arg.begin()+1); it!=arg.end(); ++it) + { + if (it->short_arg.size()==1) args()[it->short_arg] = it->params; + if (it->long_arg.size()) args()["--"+it->long_arg] = it->params; + } + // parse commandline and evaluate the arguments +#ifdef ARGS__OLD_PRE11_COMPILER + for (char** a(argv+1); a > - 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()); + { + std::string arg(*a); + if (arg.size()>1&&arg[0]=='-'&&arg[1]!='-') { // short argument +#ifdef ARGS__OLD_PRE11_COMPILER + for (std::string::iterator it(arg.begin()+1); it!=arg.end(); ++it) #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)); + for (auto it(arg.begin()+1); it!=arg.end(); ++it) #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(s).flush(); - const_cast(s)._os = &os; - } - return const_cast(s); - } - template 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<=_width-_indent) { - if (_indent) *_os<* _os; - }; - typedef basic_split split; - void show_help(const std::string& synopsis_txt="SYNOPSIS", - const std::string& description_txt="DESCRIPTION", - const std::string& options_txt="OPTIONS", - const std::string& returns_txt="RETURNS", - int max_line=80, int indent=2, int long_indent=4, - int option_len=16, int param_len=21) { - std::cout<short_arg.size()?"-"+arg->short_arg:"")+ - (arg->short_arg.size()&&arg->long_arg.size()?", ":"")+ - (arg->long_arg.size()?"--"+arg->long_arg:"")); -#ifndef ARGS__CPLUSPLUS11 - std::string a; - for (std::vector >::iterator - p(arg->params.begin()); - p!=arg->params.end(); ++p) { - std::string def(**p); - a+=(*p)->type()+(def.size()?"="+def:""); - } + { + std::string o((arg->short_arg.size()?"-"+arg->short_arg:"")+ + (arg->short_arg.size()&&arg->long_arg.size()?", ":"")+ + (arg->long_arg.size()?"--"+arg->long_arg:"")); +#ifdef ARGS__OLD_PRE11_COMPILER + std::string a; + for (std::vector >::iterator + p(arg->params.begin()); + p!=arg->params.end(); ++p) { + std::string def(**p); + a+=(*p)->type()+(def.size()?"="+def:""); + } #else - std::string a(std::accumulate(arg->params.begin(), arg->params.end(), - std::string(), - [](const std::string& s, - std::shared_ptr p) - -> std::string { - std::string def(**p); - return s+p->type()+(def.size()?"="+def:""); - })); + std::string a(std::accumulate(arg->params.begin(), arg->params.end(), + std::string(), + [](const std::string& s, + std::shared_ptr p) + -> std::string { + std::string def(**p); + return s+p->type()+(def.size()?"="+def:""); + })); #endif - std::cout<desc.size()>max_line-indent-option_len-param_len) - std::cout<desc; - else - std::cout<desc; - std::cout<desc.size()>max_line-indent-option_len-param_len) + std::cout<desc; + else + std::cout<desc; + std::cout< func(void(*fn)()) { + return + std::shared_ptr + (new args::parameter(fn)); + } + std::shared_ptr help() { + return func(args::help_no_arg); + } + std::shared_ptr exit() { + return func(args::do_exit); } - } - void help_no_arg() { - show_help(); - } - void do_exit() { - exit(1); - } - std::shared_ptr func(void(*fn)()) { - return - std::shared_ptr - (new args::parameter(fn)); - } - std::shared_ptr help() { - return func(args::help_no_arg); - } - std::shared_ptr exit() { - return func(args::do_exit); } } #endif diff --git a/src/mrw/iomanip b/src/mrw/iomanip new file mode 100644 index 0000000..4cc716d --- /dev/null +++ b/src/mrw/iomanip @@ -0,0 +1,105 @@ +/*! @file + + @id $Id$ +*/ +// 1 2 3 4 5 6 7 8 +// 45678901234567890123456789012345678901234567890123456789012345678901234567890 + +#ifndef __MRW__IOMANIP__ +#define __MRW__IOMANIP__ + +#include +#include +#include +#include + +// check if code is compiled with a new C++11 compiler +// otherwise there is a fallback wich makes everything much more compliacted +#ifndef ARGS__OLD_PRE11_COMPILER +#if __cplusplus < 201103L +/// Code is compiled with an old non C++11 standard compliant compiler +/** There are workarounds for old non C++11 compatible + compilers. These workarounds are deprecated, but will remain until + most compilers fully support C++11. So this workaround will be + removed in future releases, when support for C++11 is more + common. Only rely on this workaround, if you really have to. + @see oldcompiler for details on usage */ +#define ARGS__OLD_PRE11_COMPILER +#warning You need a C++11 compliant compiler, on gcc use option -std=c++11 +#warning emulating C++11 - this changes the way you use the library +#warning this is deprecated and will be removed in future releases +#warning refere to the library documentation for more details +#endif +#endif + + +namespace mrw { + //! IO-Manipulator to split long lines into several shorter lines. + template > + 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) +#ifdef ARGS__OLD_PRE11_COMPILER + 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(s).flush(); + const_cast(s)._os = &os; + } + return const_cast(s); + } + template 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<=_width-_indent) { + if (_indent) *_os<* _os; + }; + typedef basic_split split; +} +#endif