release 0.91
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
* Tue Apr 27 2004 Marc Wäckerlin <marc@waeckerlin.org> - mrw-c++-0.91 (mrw)
|
||||||
|
- mrw/arg.hpp: Command line argument evaluation
|
||||||
|
- mrw/smartpointer.hpp: Smart pointer implementation
|
||||||
|
- configure: Correction for Solaris
|
||||||
* Fri Apr 24 2004 Marc Wäckerlin <marc@waeckerlin.org> - mrw-c++-0.90 (mrw)
|
* Fri Apr 24 2004 Marc Wäckerlin <marc@waeckerlin.org> - mrw-c++-0.90 (mrw)
|
||||||
- initial rpm with two spec files
|
- initial rpm with two spec files
|
||||||
- test cases for libmrwexcstderr and libmrwexclog4cxx
|
- test cases for libmrwexcstderr and libmrwexclog4cxx
|
||||||
|
2
NEWS
2
NEWS
@@ -1,3 +1,5 @@
|
|||||||
|
New: Command line argument evaluation and SmartPointer
|
||||||
|
|
||||||
This is a preliminary release. Especially tests, configure
|
This is a preliminary release. Especially tests, configure
|
||||||
environment, packages and documentation are not yet finished. It
|
environment, packages and documentation are not yet finished. It
|
||||||
should already work, even though it may be not yet perfect.
|
should already work, even though it may be not yet perfect.
|
||||||
|
10
configure.in
10
configure.in
@@ -2,7 +2,7 @@
|
|||||||
AC_INIT([mrw/mrw.hpp.in])
|
AC_INIT([mrw/mrw.hpp.in])
|
||||||
PACKAGENAME=mrw-c++
|
PACKAGENAME=mrw-c++
|
||||||
MAJOR=0
|
MAJOR=0
|
||||||
MINOR=90
|
MINOR=91
|
||||||
SUPPORT=beta
|
SUPPORT=beta
|
||||||
AM_INIT_AUTOMAKE(@PACKAGENAME@, @MAJOR@.@MINOR@, [marc@waeckerlin.org])
|
AM_INIT_AUTOMAKE(@PACKAGENAME@, @MAJOR@.@MINOR@, [marc@waeckerlin.org])
|
||||||
|
|
||||||
@@ -32,11 +32,11 @@ AC_CHECK_HEADER(sys/old_procfs.h, [AM_CPPFLAGS=-D__solaris__])
|
|||||||
AC_SEARCH_LIBS(cplus_demangle, iberty, [AC_MSG_RESULT([OK])],
|
AC_SEARCH_LIBS(cplus_demangle, iberty, [AC_MSG_RESULT([OK])],
|
||||||
[AC_MSG_ERROR([Library iberty is required!])])
|
[AC_MSG_ERROR([Library iberty is required!])])
|
||||||
AC_SEARCH_LIBS(bfd_arch_list, bfd, [AC_MSG_RESULT([OK])],
|
AC_SEARCH_LIBS(bfd_arch_list, bfd, [AC_MSG_RESULT([OK])],
|
||||||
[
|
[no_bfd=true])
|
||||||
|
if [ -n "$no_bfd" ]; then
|
||||||
AC_SEARCH_LIBS(bfd_arch_list, bfd, [AC_MSG_RESULT([OK])],
|
AC_SEARCH_LIBS(bfd_arch_list, bfd, [AC_MSG_RESULT([OK])],
|
||||||
[AC_MSG_ERROR([BFD library libbfd is required])],
|
[AC_MSG_ERROR([BFD library libbfd is required])], [-lintl])
|
||||||
[-lintl])
|
fi
|
||||||
])
|
|
||||||
|
|
||||||
# Arguments
|
# Arguments
|
||||||
AM_MAINTAINER_MODE
|
AM_MAINTAINER_MODE
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
SUBDIRS = mrw
|
SUBDIRS = mrw
|
||||||
|
|
||||||
|
EXTRA_DIST = bootstrap.sh
|
||||||
|
|
||||||
nobase_include_HEADERS = mrw/auto.hpp mrw/unistd.hpp \
|
nobase_include_HEADERS = mrw/auto.hpp mrw/unistd.hpp \
|
||||||
mrw/stacktrace.hpp mrw/exception.hpp \
|
mrw/stacktrace.hpp mrw/exception.hpp \
|
||||||
mrw/exec.hpp
|
mrw/exec.hpp
|
||||||
|
686
mrw/arg.hpp
Normal file
686
mrw/arg.hpp
Normal file
@@ -0,0 +1,686 @@
|
|||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
|
//@}
|
||||||
|
}
|
@@ -42,5 +42,3 @@ int main() {
|
|||||||
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
|
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
|
||||||
return runner.run() ? 0 : 1;
|
return runner.run() ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* c = new char[100];
|
|
||||||
|
@@ -96,7 +96,7 @@ HIDE_UNDOC_CLASSES = NO
|
|||||||
# If set to NO (the default) these declarations will be included in the
|
# If set to NO (the default) these declarations will be included in the
|
||||||
# documentation.
|
# documentation.
|
||||||
|
|
||||||
HIDE_FRIEND_COMPOUNDS = NO
|
HIDE_FRIEND_COMPOUNDS = YES
|
||||||
|
|
||||||
# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
|
# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
|
||||||
# documentation blocks found inside the body of a function.
|
# documentation blocks found inside the body of a function.
|
||||||
|
25
mrw/examples/smartpointer.cpp
Normal file
25
mrw/examples/smartpointer.cpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include <mrw/smartpointer.hpp>
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public: int a;
|
||||||
|
protected: virtual void fn() {} // dynamic_cast requires a virtual function
|
||||||
|
};
|
||||||
|
|
||||||
|
class B: virtual public A {
|
||||||
|
public: int b;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int, char**) {
|
||||||
|
utl::SmartPointer<int> i1 = new int;
|
||||||
|
*i1 = 13;
|
||||||
|
utl::SmartPointer<int> i2 = i1;
|
||||||
|
utl::SmartPointer<int> i3;
|
||||||
|
if (!i3) i3 = i2;
|
||||||
|
*i2 = 666; // *i1 is now 666 too
|
||||||
|
utl::SmartPointer<A> b1 = new B;
|
||||||
|
utl::SmartPointer<B> b2 = b1; // b1 and b2 point to the same instance
|
||||||
|
b1->a = 0; // b1->b does not compile
|
||||||
|
b2->a = 1;
|
||||||
|
b2->b = 2;
|
||||||
|
return 0;
|
||||||
|
} // memory is automatically freed
|
@@ -2,6 +2,8 @@
|
|||||||
#define __MRW_EXCEPTION_HPP__
|
#define __MRW_EXCEPTION_HPP__
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <typeinfo>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace mrw {
|
namespace mrw {
|
||||||
@@ -167,11 +169,140 @@ call of fn0 successful
|
|||||||
public:
|
public:
|
||||||
exception() throw(std::bad_exception);
|
exception() throw(std::bad_exception);
|
||||||
virtual ~exception() throw();
|
virtual ~exception() throw();
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::exception::what();
|
||||||
|
}
|
||||||
const std::string& stacktrace() const throw(std::bad_exception);
|
const std::string& stacktrace() const throw(std::bad_exception);
|
||||||
private:
|
private:
|
||||||
StackTrace* _stacktrace;
|
StackTrace* _stacktrace;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::bad_alloc, but with stack trace
|
||||||
|
class bad_alloc:
|
||||||
|
virtual public mrw::exception, virtual public std::bad_alloc {
|
||||||
|
public:
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::bad_alloc::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::bad_cast, but with stack trace
|
||||||
|
class bad_cast:
|
||||||
|
virtual public mrw::exception, virtual public std::bad_cast {
|
||||||
|
public:
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::bad_cast::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::bad_exception, but with stack trace
|
||||||
|
class bad_exception:
|
||||||
|
virtual public mrw::exception, virtual public std::bad_exception {
|
||||||
|
public:
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::bad_exception::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::bad_typeid, but with stack trace
|
||||||
|
class bad_typeid:
|
||||||
|
virtual public mrw::exception, virtual public std::bad_typeid {
|
||||||
|
public:
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::bad_typeid::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::logic_error, but with stack trace
|
||||||
|
class logic_error:
|
||||||
|
virtual public mrw::exception, virtual public std::logic_error {
|
||||||
|
public:
|
||||||
|
logic_error(const std::string& arg): std::logic_error(arg) {}
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::logic_error::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::domain_error, but with stack trace
|
||||||
|
class domain_error:
|
||||||
|
virtual public mrw::exception, virtual public std::domain_error {
|
||||||
|
public:
|
||||||
|
domain_error(const std::string& arg): std::domain_error(arg) {}
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::domain_error::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::invalid_argument, but with stack trace
|
||||||
|
class invalid_argument:
|
||||||
|
virtual public mrw::exception, virtual public std::invalid_argument {
|
||||||
|
public:
|
||||||
|
invalid_argument(const std::string& arg): std::invalid_argument(arg) {}
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::invalid_argument::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::length_error, but with stack trace
|
||||||
|
class length_error:
|
||||||
|
virtual public mrw::exception, virtual public std::length_error {
|
||||||
|
public:
|
||||||
|
length_error(const std::string& arg): std::length_error(arg) {}
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::length_error::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::out_of_range, but with stack trace
|
||||||
|
class out_of_range:
|
||||||
|
virtual public mrw::exception, virtual public std::out_of_range {
|
||||||
|
public:
|
||||||
|
out_of_range(const std::string& arg): std::out_of_range(arg) {}
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::out_of_range::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::runtime_error, but with stack trace
|
||||||
|
class runtime_error:
|
||||||
|
virtual public mrw::exception, virtual public std::runtime_error {
|
||||||
|
public:
|
||||||
|
runtime_error(const std::string& arg): std::runtime_error(arg) {}
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::runtime_error::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::overflow_error, but with stack trace
|
||||||
|
class overflow_error:
|
||||||
|
virtual public mrw::exception, virtual public std::overflow_error {
|
||||||
|
public:
|
||||||
|
overflow_error(const std::string& arg): std::overflow_error(arg) {}
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::overflow_error::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::range_error, but with stack trace
|
||||||
|
class range_error:
|
||||||
|
virtual public mrw::exception, virtual public std::range_error {
|
||||||
|
public:
|
||||||
|
range_error(const std::string& arg): std::range_error(arg) {}
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::range_error::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Replacement for @c std::underflow_error, but with stack trace
|
||||||
|
class underflow_error:
|
||||||
|
virtual public mrw::exception, virtual public std::underflow_error {
|
||||||
|
public:
|
||||||
|
underflow_error(const std::string& arg): std::underflow_error(arg) {}
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return std::underflow_error::what();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,9 +12,10 @@ EXTRA_DIST = test.dat ${examples_DATA} ${html_DATA} ${pdf_DATA}
|
|||||||
lib_LTLIBRARIES = libmrw.la libmrwexcstderr.la libmrwexclog4cxx.la
|
lib_LTLIBRARIES = libmrw.la libmrwexcstderr.la libmrwexclog4cxx.la
|
||||||
|
|
||||||
libmrw_la_SOURCES = mrw.hpp \
|
libmrw_la_SOURCES = mrw.hpp \
|
||||||
auto.hpp auto.cpp unistd.hpp \
|
auto.hpp auto.cpp unistd.hpp smartpointer.hpp \
|
||||||
stacktrace.hpp stacktrace.cpp exception.hpp exception.cpp \
|
stacktrace.hpp stacktrace.cpp exception.hpp exception.cpp \
|
||||||
exec.hpp exec.cpp
|
exec.hpp exec.cpp \
|
||||||
|
arg.hpp
|
||||||
libmrw_la_LDFLAGS = -version-info @MAJOR@:@MINOR@
|
libmrw_la_LDFLAGS = -version-info @MAJOR@:@MINOR@
|
||||||
|
|
||||||
libmrwexcstderr_la_SOURCES = autostacktracestderr.cpp
|
libmrwexcstderr_la_SOURCES = autostacktracestderr.cpp
|
||||||
@@ -25,10 +26,14 @@ libmrwexclog4cxx_la_SOURCES = autostacktracelog4cxx.cpp
|
|||||||
libmrwexclog4cxx_la_LDFLAGS = -version-info @MAJOR@:@MINOR@
|
libmrwexclog4cxx_la_LDFLAGS = -version-info @MAJOR@:@MINOR@
|
||||||
libmrwexclog4cxx_la_LIBADD = -lmrw
|
libmrwexclog4cxx_la_LIBADD = -lmrw
|
||||||
|
|
||||||
check_PROGRAMS = auto_test exec_test stacktrace_test mrwexcstderr_test mrwexclog4cxx_test
|
check_PROGRAMS = auto_test smartpointer_test exec_test \
|
||||||
|
stacktrace_test mrwexcstderr_test mrwexclog4cxx_test
|
||||||
auto_test_SOURCES = auto_test.cpp
|
auto_test_SOURCES = auto_test.cpp
|
||||||
auto_test_CPPFLAGS = -I.. -g3
|
auto_test_CPPFLAGS = -I.. -g3
|
||||||
auto_test_LDADD = -lmrw -lcppunit
|
auto_test_LDADD = -lmrw -lcppunit
|
||||||
|
smartpointer_test_SOURCES = smartpointer_test.cpp
|
||||||
|
smartpointer_test_CPPFLAGS = -I.. -g3
|
||||||
|
smartpointer_test_LDADD = -lmrw -lcppunit
|
||||||
exec_test_SOURCES = exec_test.cpp
|
exec_test_SOURCES = exec_test.cpp
|
||||||
exec_test_CPPFLAGS = -I.. -g3
|
exec_test_CPPFLAGS = -I.. -g3
|
||||||
exec_test_LDADD = -lmrw -lcppunit
|
exec_test_LDADD = -lmrw -lcppunit
|
||||||
|
72
mrw/simpletrace.hpp
Normal file
72
mrw/simpletrace.hpp
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#ifndef __MRW_SIMPLETRACE_HPP__
|
||||||
|
#define __MRW_SIMPLETRACE_HPP__
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// GENERIC TRACER FOR TESTS ---------------------------------------------------
|
||||||
|
// (without file/line)
|
||||||
|
#ifndef __GNUG__
|
||||||
|
#define METHOD(name) mrw::FnTrace fnTrace(this, name)
|
||||||
|
#define FUNCTION(name) mrw::FnTrace fnTrace(0, name)
|
||||||
|
#else
|
||||||
|
#define METHOD mrw::FnTrace fnTrace(this, __FUNCTION__)
|
||||||
|
#define FUNCTION mrw::FnTrace fnTrace(0, __FUNCTION__)
|
||||||
|
#endif
|
||||||
|
#define CALL(name) fnTrace.call(name)
|
||||||
|
#define TRACE(name) fnTrace.trace(name)
|
||||||
|
#define TRACE_OFF mrw::FnTrace::off()
|
||||||
|
#define TRACE_ON mrw::FnTrace::on()
|
||||||
|
#define NO_TRACE mrw::NoTrace noTrace;
|
||||||
|
|
||||||
|
namespace mrw {
|
||||||
|
class FnTrace {
|
||||||
|
public:
|
||||||
|
FnTrace(const void* addr, const std::string& name):
|
||||||
|
_addr(addr), _name(name) {
|
||||||
|
if (_off==0)
|
||||||
|
std::cout<<std::hex<<std::setw(15)<<_addr<<": "<<std::dec
|
||||||
|
<<std::setw(2+_level)<<std::setfill(' ')<<"\\ "
|
||||||
|
<<_name<<std::endl;
|
||||||
|
++_level;
|
||||||
|
}
|
||||||
|
~FnTrace() {
|
||||||
|
--_level;
|
||||||
|
if (_off==0)
|
||||||
|
std::cout<<std::hex<<std::setw(15)<<_addr<<": "<<std::dec
|
||||||
|
<<std::setw(2+_level)<<std::setfill(' ')<<"/ "<<_name
|
||||||
|
<<std::endl;
|
||||||
|
}
|
||||||
|
void call(const std::string& name) {
|
||||||
|
if (_off==0)
|
||||||
|
std::cout<<std::hex<<std::setw(15)<<_addr<<": "<<std::dec
|
||||||
|
<<std::setw(4+_level)<<std::setfill(' ')<<" -> "<<name
|
||||||
|
<<std::endl;
|
||||||
|
}
|
||||||
|
void trace(const std::string& name) {
|
||||||
|
if (_off==0)
|
||||||
|
std::cout<<std::hex<<std::setw(15)<<_addr<<": "<<std::dec
|
||||||
|
<<std::setw(4+_level)<<std::setfill(' ')<<" **** "<<name
|
||||||
|
<<" **** "<<std::endl;
|
||||||
|
}
|
||||||
|
static void off() {
|
||||||
|
++_off;
|
||||||
|
}
|
||||||
|
static void on() {
|
||||||
|
if (_off>0) --_off;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
const void* _addr;
|
||||||
|
const std::string _name;
|
||||||
|
static unsigned int _level;
|
||||||
|
static unsigned int _off;
|
||||||
|
};
|
||||||
|
unsigned int FnTrace::_level(0);
|
||||||
|
unsigned int FnTrace::_off(0);
|
||||||
|
class NoTrace {
|
||||||
|
public:
|
||||||
|
NoTrace() {TRACE_OFF;}
|
||||||
|
~NoTrace() {TRACE_ON;}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
137
mrw/smartpointer.hpp
Normal file
137
mrw/smartpointer.hpp
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
#ifndef __MRW__SMARTPOINTER_HPP__
|
||||||
|
#define __MRW__SMARTPOINTER_HPP__
|
||||||
|
|
||||||
|
namespace mrw {
|
||||||
|
|
||||||
|
class PointerCounter {
|
||||||
|
private:
|
||||||
|
unsigned int _cnt;
|
||||||
|
public:
|
||||||
|
PointerCounter():
|
||||||
|
_cnt(1) {
|
||||||
|
}
|
||||||
|
PointerCounter* incr() {
|
||||||
|
++_cnt;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
int decr() {
|
||||||
|
return --_cnt;
|
||||||
|
}
|
||||||
|
int get() {
|
||||||
|
return _cnt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SmartPointerParent {
|
||||||
|
protected:
|
||||||
|
template<class TYPE>
|
||||||
|
PointerCounter* getCounter(TYPE& sp) {
|
||||||
|
return sp._cnt;
|
||||||
|
}
|
||||||
|
template<class TYPE>
|
||||||
|
typename TYPE::Pointer getPointer(TYPE& sp) {
|
||||||
|
return sp._ptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @addtogroup AutoTools */
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/** @brief Smart Pointer Implementation
|
||||||
|
@pre #include <mrw/smartpointer.hpp>
|
||||||
|
|
||||||
|
This is a smart pointer that can be casted withing the
|
||||||
|
inheritance of the pointer it is storing.
|
||||||
|
|
||||||
|
A smart pointer is a pointer that is automatically cleaned up
|
||||||
|
when it is no more referenced. Therefore you only allocate
|
||||||
|
memory, but you never free it, just as in Java, cleaning up is
|
||||||
|
done behind the scenes. If you assign a smart pointer to another
|
||||||
|
smart pointer, both point to the same memory. A counter counts
|
||||||
|
the number of references to the object and frees it as soon as
|
||||||
|
the last smart pointer pointing to the same memory has been
|
||||||
|
destroyed.
|
||||||
|
|
||||||
|
A smart pointer is used just as a normal pointer, except that
|
||||||
|
you can assign it only to other smart pointers, not to ordinary
|
||||||
|
pointers, and you don't have to delete the memory allocated. Any
|
||||||
|
memory assigned to a smart pointer is consumed and mustn't be
|
||||||
|
used any more. Never allocate a smart pointer with
|
||||||
|
<code>new</code>, but only the pointer that is stored in the
|
||||||
|
smart pointer!
|
||||||
|
|
||||||
|
@note memory assigned to a smart pointer is consumed
|
||||||
|
*/
|
||||||
|
template<class TYPE> class SmartPointer: public SmartPointerParent {
|
||||||
|
private:
|
||||||
|
typedef TYPE* Pointer;
|
||||||
|
PointerCounter* _cnt;
|
||||||
|
TYPE* _ptr;
|
||||||
|
private:
|
||||||
|
void drop() {
|
||||||
|
if (_cnt && !_cnt->decr()) {
|
||||||
|
delete _cnt; _cnt=0;
|
||||||
|
delete _ptr; _ptr=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
friend class SmartPointerParent;
|
||||||
|
friend class SmartPointerTest;
|
||||||
|
public:
|
||||||
|
SmartPointer():
|
||||||
|
_cnt(0), _ptr(0) {
|
||||||
|
}
|
||||||
|
SmartPointer(const SmartPointer<TYPE>& o):
|
||||||
|
_cnt(o._cnt?o._cnt->incr():0), _ptr(o._ptr) {
|
||||||
|
}
|
||||||
|
SmartPointer(TYPE* ptr):
|
||||||
|
_cnt(ptr ? new PointerCounter : 0), _ptr(ptr) {
|
||||||
|
}
|
||||||
|
template<class OTHER> SmartPointer(const SmartPointer<OTHER>& o):
|
||||||
|
_cnt(0), _ptr(dynamic_cast<TYPE*>(getPointer(o))) {
|
||||||
|
if (_ptr) _cnt = getCounter(o)->incr();
|
||||||
|
}
|
||||||
|
~SmartPointer() {
|
||||||
|
drop();
|
||||||
|
}
|
||||||
|
SmartPointer& operator=(const SmartPointer<TYPE>& o) {
|
||||||
|
if (o._ptr==_ptr) return *this;
|
||||||
|
drop();
|
||||||
|
_cnt = o._cnt ? o._cnt->incr() : 0;
|
||||||
|
_ptr = o._ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
SmartPointer& operator=(TYPE* ptr) {
|
||||||
|
if (ptr==_ptr) return *this;
|
||||||
|
drop();
|
||||||
|
_cnt = ptr ? new PointerCounter : 0;
|
||||||
|
_ptr = ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
template<class OTHER>
|
||||||
|
SmartPointer& operator=(const SmartPointer<OTHER>& o) {
|
||||||
|
if (getPointer(o)==_ptr) return *this;
|
||||||
|
drop();
|
||||||
|
_ptr = dynamic_cast<TYPE*>(getPointer(o));
|
||||||
|
_cnt = _ptr ? getCounter(o)->incr() : 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
TYPE& operator*() {
|
||||||
|
return *_ptr;
|
||||||
|
}
|
||||||
|
const TYPE& operator*() const {
|
||||||
|
return *_ptr;
|
||||||
|
}
|
||||||
|
TYPE* const operator->() {
|
||||||
|
return _ptr;
|
||||||
|
}
|
||||||
|
const TYPE* const operator->() const {
|
||||||
|
return _ptr;
|
||||||
|
}
|
||||||
|
operator bool() {
|
||||||
|
return _ptr!=0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//@}
|
||||||
|
}
|
||||||
|
#endif
|
@@ -53,43 +53,6 @@ namespace mrw {
|
|||||||
- a system with ELF binaries (LINUX, Solaris, ...)
|
- a system with ELF binaries (LINUX, Solaris, ...)
|
||||||
- debug information, compile option @c -g
|
- debug information, compile option @c -g
|
||||||
- it must be linked with @c -libery and @c -lbfd
|
- it must be linked with @c -libery and @c -lbfd
|
||||||
|
|
||||||
@subsection sttech Technology
|
|
||||||
|
|
||||||
On GNU glibc based systems (Linux), the stack trace is collected
|
|
||||||
with GNU glibc's function @c backtrace(). On other systems
|
|
||||||
(Solaris) it is collected using the GNU gcc's internal function @c
|
|
||||||
__builtin_return_address(). With both functions, at most 50 steps
|
|
||||||
back are collected.
|
|
||||||
|
|
||||||
The evaluation is not done with the glibc library function @c
|
|
||||||
backtrace_symbols(), because this function is unable to print
|
|
||||||
the source file name and line number information. Instead of
|
|
||||||
this, the executable binary is loaded into the memory and
|
|
||||||
evaluated using the bdf library functions. For this the stack
|
|
||||||
tracer needs to know how to find out which executable is
|
|
||||||
running. It is possible to get this information automatically on
|
|
||||||
Linux and Solaris. On other systems, I don't have this
|
|
||||||
information, but you can either tell me, and I integrate support
|
|
||||||
for your system (when I have time to do it), or provide the
|
|
||||||
executable file name as an argument to @c
|
|
||||||
mrw::StackTrace::createSymtable().
|
|
||||||
|
|
||||||
@subsection stdrawbacks Draw Backs
|
|
||||||
|
|
||||||
Unfortunately it is not possible to extract the source file name
|
|
||||||
and line number information if the executable was not compiled
|
|
||||||
with debug option @c -g. But what's worse, it is not possible to
|
|
||||||
ger symbolic information from libraries linked to the
|
|
||||||
executable. Perhaps it could be possible, if I'd add a
|
|
||||||
possibility to read and evaluate these libraries, but that's for
|
|
||||||
a future release.
|
|
||||||
|
|
||||||
@todo Add support to read debugging information from libraries
|
|
||||||
that are linked to the executable.
|
|
||||||
|
|
||||||
@todo Add support for alternative symbol evaluation using @c
|
|
||||||
backtrace_symbols.
|
|
||||||
*/
|
*/
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
@@ -118,6 +81,43 @@ namespace mrw {
|
|||||||
library.
|
library.
|
||||||
|
|
||||||
@note Symbol evaluation requires the ELF library and an ELF system.
|
@note Symbol evaluation requires the ELF library and an ELF system.
|
||||||
|
|
||||||
|
@section sttech Technology
|
||||||
|
|
||||||
|
On GNU glibc based systems (Linux), the stack trace is collected
|
||||||
|
with GNU glibc's function @c backtrace(). On other systems
|
||||||
|
(Solaris) it is collected using the GNU gcc's internal function @c
|
||||||
|
__builtin_return_address(). With both functions, at most 50 steps
|
||||||
|
back are collected.
|
||||||
|
|
||||||
|
The evaluation is not done with the glibc library function @c
|
||||||
|
backtrace_symbols(), because this function is unable to print
|
||||||
|
the source file name and line number information. Instead of
|
||||||
|
this, the executable binary is loaded into the memory and
|
||||||
|
evaluated using the bdf library functions. For this the stack
|
||||||
|
tracer needs to know how to find out which executable is
|
||||||
|
running. It is possible to get this information automatically on
|
||||||
|
Linux and Solaris. On other systems, I don't have this
|
||||||
|
information, but you can either tell me, and I integrate support
|
||||||
|
for your system (when I have time to do it), or provide the
|
||||||
|
executable file name as an argument to @c
|
||||||
|
mrw::StackTrace::createSymtable().
|
||||||
|
|
||||||
|
@section stdrawbacks Draw Backs
|
||||||
|
|
||||||
|
Unfortunately it is not possible to extract the source file name
|
||||||
|
and line number information if the executable was not compiled
|
||||||
|
with debug option @c -g. But what's worse, it is not possible to
|
||||||
|
ger symbolic information from libraries linked to the
|
||||||
|
executable. Perhaps it could be possible, if I'd add a
|
||||||
|
possibility to read and evaluate these libraries, but that's for
|
||||||
|
a future release.
|
||||||
|
|
||||||
|
@todo Add support to read debugging information from libraries
|
||||||
|
that are linked to the executable.
|
||||||
|
|
||||||
|
@todo Add support for alternative symbol evaluation using @c
|
||||||
|
backtrace_symbols.
|
||||||
*/
|
*/
|
||||||
class StackTrace {
|
class StackTrace {
|
||||||
public:
|
public:
|
||||||
|
Reference in New Issue
Block a user