release 0.91

master
Marc Wäckerlin 20 years ago
parent 93696ef645
commit eb6daf08ba
  1. 4
      ChangeLog
  2. 2
      NEWS
  3. 12
      configure.in
  4. 2
      makefile.am
  5. 686
      mrw/arg.hpp
  6. 2
      mrw/auto_test.cpp
  7. 2
      mrw/doxyfile.in
  8. 25
      mrw/examples/smartpointer.cpp
  9. 131
      mrw/exception.hpp
  10. 11
      mrw/makefile.am
  11. 72
      mrw/simpletrace.hpp
  12. 137
      mrw/smartpointer.hpp
  13. 60
      mrw/stacktrace.hpp

@ -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)
- initial rpm with two spec files
- test cases for libmrwexcstderr and libmrwexclog4cxx

@ -1,3 +1,5 @@
New: Command line argument evaluation and SmartPointer
This is a preliminary release. Especially tests, configure
environment, packages and documentation are not yet finished. It
should already work, even though it may be not yet perfect.

@ -2,7 +2,7 @@
AC_INIT([mrw/mrw.hpp.in])
PACKAGENAME=mrw-c++
MAJOR=0
MINOR=90
MINOR=91
SUPPORT=beta
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_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])],
[AC_MSG_ERROR([BFD library libbfd is required])],
[-lintl])
])
[no_bfd=true])
if [ -n "$no_bfd" ]; then
AC_SEARCH_LIBS(bfd_arch_list, bfd, [AC_MSG_RESULT([OK])],
[AC_MSG_ERROR([BFD library libbfd is required])], [-lintl])
fi
# Arguments
AM_MAINTAINER_MODE

@ -1,5 +1,7 @@
SUBDIRS = mrw
EXTRA_DIST = bootstrap.sh
nobase_include_HEADERS = mrw/auto.hpp mrw/unistd.hpp \
mrw/stacktrace.hpp mrw/exception.hpp \
mrw/exec.hpp

@ -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());
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
# documentation.
HIDE_FRIEND_COMPOUNDS = NO
HIDE_FRIEND_COMPOUNDS = YES
# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
# documentation blocks found inside the body of a function.

@ -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__
#include <exception>
#include <stdexcept>
#include <typeinfo>
#include <string>
namespace mrw {
@ -167,11 +169,140 @@ call of fn0 successful
public:
exception() throw(std::bad_exception);
virtual ~exception() throw();
virtual const char* what() const throw() {
return std::exception::what();
}
const std::string& stacktrace() const throw(std::bad_exception);
private:
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
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 \
exec.hpp exec.cpp
exec.hpp exec.cpp \
arg.hpp
libmrw_la_LDFLAGS = -version-info @MAJOR@:@MINOR@
libmrwexcstderr_la_SOURCES = autostacktracestderr.cpp
@ -25,10 +26,14 @@ libmrwexclog4cxx_la_SOURCES = autostacktracelog4cxx.cpp
libmrwexclog4cxx_la_LDFLAGS = -version-info @MAJOR@:@MINOR@
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_CPPFLAGS = -I.. -g3
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_CPPFLAGS = -I.. -g3
exec_test_LDADD = -lmrw -lcppunit

@ -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

@ -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,8 +53,36 @@ namespace mrw {
- a system with ELF binaries (LINUX, Solaris, ...)
- debug information, compile option @c -g
- it must be linked with @c -libery and @c -lbfd
*/
//@{
/** @brief store and print a stack trace of the actual position in code
@pre #include <mrw/stacktrace.hpp>
In the constructor, a stack trace is stored, but not yet
evaluated. Therefore storing a stack trace is relatively
fast. The evaluation is done when the stack trace is printed on
a stream or converted to a string. "Evaluation" means, that the
addresses are mapped to the correspoding symbols, the method
names, sorce file names and line numbers are evaluated.
@note Method StackTrace::createSymtable must be called exactely
once, before evaluating the first stack trace.Best place is the
first line of the @c main function.
@note This class requires libbfd an libiberty. Debug information
is required for compiling. You nee the compile option @c -g, or
even better @c -ggdb3. To link, you need @c -lmrw, @c -lbfd and
@c -liberty.
@subsection sttech Technology
@note The stack trace is known to work perfectly on Linux and
Solaris both with GNU gcc compiler. But it should work with the
GNU compiler on all systems, or wherever there is a glibc
library.
@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
@ -75,7 +103,7 @@ namespace mrw {
executable file name as an argument to @c
mrw::StackTrace::createSymtable().
@subsection stdrawbacks Draw Backs
@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
@ -91,34 +119,6 @@ namespace mrw {
@todo Add support for alternative symbol evaluation using @c
backtrace_symbols.
*/
//@{
/** @brief store and print a stack trace of the actual position in code
@pre #include <mrw/stacktrace.hpp>
In the constructor, a stack trace is stored, but not yet
evaluated. Therefore storing a stack trace is relatively
fast. The evaluation is done when the stack trace is printed on
a stream or converted to a string. "Evaluation" means, that the
addresses are mapped to the correspoding symbols, the method
names, sorce file names and line numbers are evaluated.
@note Method StackTrace::createSymtable must be called exactely
once, before evaluating the first stack trace.Best place is the
first line of the @c main function.
@note This class requires libbfd an libiberty. Debug information
is required for compiling. You nee the compile option @c -g, or
even better @c -ggdb3. To link, you need @c -lmrw, @c -lbfd and
@c -liberty.
@note The stack trace is known to work perfectly on Linux and
Solaris both with GNU gcc compiler. But it should work with the
GNU compiler on all systems, or wherever there is a glibc
library.
@note Symbol evaluation requires the ELF library and an ELF system.
*/
class StackTrace {
public:
//............................................................... typedefs

Loading…
Cancel
Save