middle of porting; unstable, don't checkout; refs #1

This commit is contained in:
Marc Wäckerlin
2011-12-11 09:35:56 +00:00
parent 3bda8f9e64
commit e5441e3465
32 changed files with 0 additions and 14 deletions

View File

@@ -1,138 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.3 2005/02/08 12:31:36 marc
new static methods to simplify access to options
Revision 1.2 2004/11/25 18:26:04 marc
Constness corrected
Revision 1.1 2004/08/28 16:13:42 marc
mrw-c++-0.92 (mrw)
- new file: version.cxx
- new file header for all sources
- work around warning in mrw::auto<T>
- possibility to compile without log4cxx
- work around bugs in demangle.h and libiberty.h
- corrections in documentation
- added simple tracing mechanism
- more warnings
- small corrections in Auto<>::Free and a new test for it
- possibility to compile without stack trace
*/
#include <mrw/arg.hxx>
#include <mrw/exception.hxx>
namespace mrw {
const std::string& Param::Value::toString() const throw(std::exception) {
throw mrw::bad_cast();
}
int Param::Value::toInt() const throw(std::exception) {
throw mrw::bad_cast();
}
bool Param::Value::toBool() const throw(std::exception) {
throw mrw::bad_cast();
}
void Param::IntValue::operator=(const std::string& s) throw(std::exception) {
if (!(std::stringstream(s)>>_i)) throw mrw::bad_cast();
}
const mrw::SmartPointer<Param::Value>& Param::operator[](unsigned int i) const
throw(std::exception) {
if (i<_params.size()) return _params[i];
throw mrw::out_of_range
(((std::stringstream&)
(std::stringstream()<<"check failed: "
<<i<<'<'<<_params.size())).str());
}
mrw::SmartPointer<Param::Value>& Param::setable(unsigned int i)
throw(std::exception) {
if (i<_params.size()) return _params[i];
throw mrw::out_of_range
(((std::stringstream&)
(std::stringstream()<<"check failed: "
<<i<<'<'<<_params.size())).str());
}
Args& Args::operator<<(const mrw::Opt& opt) throw(std::exception) {
// 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;
}
Args& Args::operator<<(char const*const*const argv) throw(std::exception) {
if (_argc<0)
throw mrw::invalid_argument("argc was not set when shifting argv");
return parse(_argc, argv);
}
const Opt& Args::find(char c) const throw(std::exception) {
ShortOpts::const_iterator it(_shortopts.find(c));
if (it==_shortopts.end()) throw mrw::out_of_range(std::string(1, c));
return *it->second;
}
const Opt& Args::find(const std::string& s) const throw(std::exception) {
LongOpts::const_iterator it(_longopts.find(s));
if (it==_longopts.end()) throw mrw::out_of_range(s);
return *it->second;
}
Args& Args::parse(int argc, char const*const*const argv)
throw(std::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;
}
}

View File

@@ -1,92 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.5 2005/04/07 20:55:21 marc
Oops, there's a make distcheck...? Now it works.
Revision 1.4 2004/11/25 18:27:03 marc
additional test for release and reset
Revision 1.3 2004/08/28 16:21:25 marc
mrw-c++-0.92 (mrw)
- new file: version.cxx
- new file header for all sources
- work around warning in mrw::auto<T>
- possibility to compile without log4cxx
- work around bugs in demangle.h and libiberty.h
- corrections in documentation
- added simple tracing mechanism
- more warnings
- small corrections in Auto<>::Free and a new test for it
- possibility to compile without stack trace
*/
#include <mrw/auto.hxx>
#include <mrw/stdext.hxx> // ifelse
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <fcntl.h> // open
#include <string.h> // strncpy
#include <stdlib.h> // getenv
class AutoTest: public CppUnit::TestFixture {
public:
void AutoFile() {
char c(0);
int i(-1);
{
mrw::AutoFile a;
CPPUNIT_ASSERT(a==-1); // init as -1
i = a = open((std::string(mrw::ifelse(getenv("srcdir"), "."))
+"/test.dat").c_str(), O_RDONLY);
CPPUNIT_ASSERT(i==a && a>0); // file is now open
mrw::AutoFile b(a);
CPPUNIT_ASSERT(a==-1 && i==b); // b has taken ownership
CPPUNIT_ASSERT(read(b, &c, 1)==1 && c=='H'); // file is good
mrw::AutoFile cc(i);
CPPUNIT_ASSERT(i==b && b==cc); // ooops, two owner!
cc.release();
CPPUNIT_ASSERT(i==b && cc==-1); // it's ok now
b = open("test.dat", O_RDONLY);
//close(i);
CPPUNIT_ASSERT(read(i, &c, 1)==-1); // old file is closed
i = b.reset();
CPPUNIT_ASSERT(read(i, &c, 1)==-1); // new file is closed
i = a = open("test.dat", O_RDONLY);
}
CPPUNIT_ASSERT(read(i, &c, 1)==-1); // file is closed now
}
void AutoFree() {
const char C[] = "Hello World";
mrw::Auto<char*>::Free c(malloc(sizeof(C)));
CPPUNIT_ASSERT(c);
strncpy(c, C, sizeof(C));
CPPUNIT_ASSERT(std::string(c)==C);
mrw::Auto<char*>::Free c2(c.release());
CPPUNIT_ASSERT(c==0 && c2!=0);
CPPUNIT_ASSERT(std::string(c2)==C);
c2.reset();
CPPUNIT_ASSERT(c2==0);
}
CPPUNIT_TEST_SUITE(AutoTest);
CPPUNIT_TEST(AutoFile);
CPPUNIT_TEST(AutoFree);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(AutoTest);
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,262 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#ifndef __GNUG__
#error GNU C++ Compiler is required for automatical function trace
#endif
#include <mrw/string.hxx>
#include <sstream>
#include <iomanip>
#include <mrw/stacktrace.hxx>
#include <log4cxx/logger.h>
#if (__GNUC__==3 && __GNUC_MINOR__<4 || __GNUC__<3) \
&& defined(_REENTRANT) && !defined(_MT)
#define _MT
#endif
// these are special built in functions of GNU Compiler Collection
extern "C" void __cyg_profile_func_enter (void *, void *) __attribute__((no_instrument_function));
extern "C" void __cyg_profile_func_exit (void *, void *) __attribute__((no_instrument_function));
// support for log4cxx 0.9.7 and for new CVS version
#ifndef LOG4CXX_LOCATION
# define MRW_LOG4CXX_LOCATION pos.file.c_str(), pos.line
#define MRW_LEVEL_DEBUG ::log4cxx::Level::DEBUG
#define MRW_LEVEL_INFO ::log4cxx::Level::INFO
#define MRW_LEVEL_WARN ::log4cxx::Level::WARN
#define MRW_LEVEL_ERROR ::log4cxx::Level::ERROR
#define MRW_LEVEL_FATAL ::log4cxx::Level::FATAL
#else
# define LOG4CXX_CVS
# define MRW_LOG4CXX_LOCATION \
::log4cxx::spi::LocationInfo(pos.file.c_str(), pos.function.c_str(), pos.line)
#define MRW_LEVEL_DEBUG ::log4cxx::Level::getDebug()
#define MRW_LEVEL_INFO ::log4cxx::Level::getInfo()
#define MRW_LEVEL_WARN ::log4cxx::Level::getWarn()
#define MRW_LEVEL_ERROR ::log4cxx::Level::getError()
#define MRW_LEVEL_FATAL ::log4cxx::Level::getFatal()
#endif
namespace mrw {
struct ThreadInfo {
int level;
bool recurse;
};
#ifdef _MT
static __thread ThreadInfo info = {0, false};
#else
static ThreadInfo info = {0, false};
#endif
static bool mainPassed(false);
class Lock {
public:
Lock() __attribute__((no_instrument_function));
~Lock() __attribute__((no_instrument_function));
};
// workaround doxygen problem:
// - the C++ compiler compiles the following code
// - doxygen ignores it
#ifndef LET_DOXYGEN_IGNORE_THIS // doxygen can't match with __attribute__ above
Lock::Lock() {
info.recurse = true;
}
Lock::~Lock() {
info.recurse = false;
}
#endif
}
extern "C" int main(int, char**);
/** @addtogroup FunctionTrace
@note There is also a fully automagic function trace, similar to
@ref AutoTrace. It is described in @ref AutoFunctionTrace
and requires the GNU Compiler Collection gcc, because it
makes use of a proprietary compiler feature. */
//@{
/** @defgroup AutoFunctionTrace Automatic Function Trace for GNU g++
If you compile your program with GNU g++&nbsp;/ gcc, and you want
to add function tracing without changing a single line of your
code, here's the solution:
If you link to the library @c libmrwautofunctiontracelog4cxx using
a linker option such as: @c -lmrwautofunctiontracelog4cxx and you
must enable the GNU Compiler Collection specific function trace
feature with compile and link option @c -finstrument-functions
then you get an automatical function trace, that traces to level
@c DEBUG using the log4cxx library. You don't need to change a single
line in your code!
This feature depends on:
- the GNU C++ compiler gcc
- @ref mrw::StackTrace
- log4cxx http://logging.apache.org/log4cxx
- optional: boost for thread support http://boost.org
The logger hiararchy name is: @c
"mrw.fn.<full-method-name>" where @c
<full-method-name> is the full name of the method, including
namespace and class name, seperated not by double colon @c :: but
by single dots @c . as it is common use in log4cxx. This way, you
can enable or disable the function trace per namespace, per class
or even per method.
The function trace does not start, before the program @c main is
reached! Only the calls within the @c main are traced, but not during
the initialisation and destruction of static members. This is
necessary, because otherwise access the incompletely initialized
MRW-C++ library itself may cause a crash.
A good default configuration is given in @ref AutoInitLog4cxx.
Depending on your log4cxx configuration, a function trace may look
e.g. like this (very simple configuration with very few additional
information):
@verbatim
mrw.fn.anotherFunction \ anotherFunction()
mrw.fn.HalloWelt.fn1 \ HalloWelt::fn1()
mrw.fn.HalloWelt.fn \ HalloWelt::fn()
mrw.fn.HalloWelt.A.method \ HalloWelt::A::method()
mrw.fn.HalloWelt.A.method / HalloWelt::A::method()
mrw.fn.HalloWelt.A.method \ HalloWelt::A::method()
mrw.fn.HalloWelt.A.method / HalloWelt::A::method()
mrw.fn.HalloWelt.fn / HalloWelt::fn()
mrw.fn.HalloWelt.fn \ HalloWelt::fn()
mrw.fn.HalloWelt.A.method \ HalloWelt::A::method()
mrw.fn.HalloWelt.A.method / HalloWelt::A::method()
mrw.fn.HalloWelt.A.method \ HalloWelt::A::method()
mrw.fn.HalloWelt.A.method / HalloWelt::A::method()
mrw.fn.HalloWelt.fn / HalloWelt::fn()
mrw.fn.HalloWelt.fn1 / HalloWelt::fn1()
mrw.fn.anotherFunction / anotherFunction()
@endverbatim
@note The configurator is not installed automatically. If you
want to trace e.g. on the console, you have to call @c
log4cxx::BasicConfigurator::configure(); as first statement
in your @c main().
@see @ref AutoInitLog4cxx if you also want to automatically
configure @c log4cxx.
@section AutoFunctionTraceThread Multithreading
Multithreading is also supported, then you need to link to the
thread safe compilat of the library @c
libmrwautofunctiontracelog4cxx-mt with option @c
-libmrwautofunctiontracelog4cxx-mt and you need the option @c
-pthread in addition to @c -finstrument-functions which is still
required.
Thread support requires the boost thread library. See
http://boost.org for details.
*/
//@{
extern "C" void __cyg_profile_func_enter(void *this_fn, void*) {
if (!mrw::mainPassed)
if (this_fn == (void*)&::main) // not ANSI C++ conform...
mrw::mainPassed=true;
else
return;
try {
if (mrw::info.recurse) return;
mrw::Lock lock;
{
static bool init(mrw::StackTrace::createSymtable());
if (!init) return;
const mrw::StackTrace::CodePos& pos(mrw::StackTrace::translate(this_fn));
std::string hierarchy(pos.function);
for (std::string::size_type p(0);
(p=hierarchy.find("::", p))!=std::string::npos;
hierarchy.replace(p, 2, "."));
hierarchy.erase(hierarchy.rfind('('));
std::string::size_type p
(hierarchy.rfind(' ', std::min(hierarchy.find('<'),
hierarchy.find("operator"))));
if (p!=std::string::npos) hierarchy.erase(0, p+1);
// hierarchy.erase
// (hierarchy.find_first_not_of
// ("qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM1234567890_."));
if (hierarchy=="") hierarchy = "global";
std::string name("mrw.fn."+hierarchy);
log4cxx::Logger* logger
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
if (logger->isDebugEnabled()) {
std::basic_ostringstream<log4cxx::String::value_type> ss;
ss<<std::setw(2+mrw::info.level++)
<<std::setfill(log4cxx::String::value_type(' '))
<<"\\ "<<log4cxx::String(pos.function.begin(), pos.function.end());
logger->forcedLog(MRW_LEVEL_DEBUG, ss.str(),
MRW_LOG4CXX_LOCATION);
}
}
} catch (...) {}
}
extern "C" void __cyg_profile_func_exit(void *this_fn, void*) {
if (!mrw::mainPassed)
return;
else
if (this_fn == (void*)&::main) { // not ANSI C++ conform...
mrw::mainPassed=false;
return;
}
try {
if (mrw::info.recurse || mrw::info.level==0) return;
mrw::Lock lock;
{
const mrw::StackTrace::CodePos& pos(mrw::StackTrace::translate(this_fn));
std::string hierarchy(pos.function);
for (std::string::size_type p(0);
(p=hierarchy.find("::", p))!=std::string::npos;
hierarchy.replace(p, 2, "."));
hierarchy.erase(hierarchy.rfind('('));
std::string::size_type p
(hierarchy.rfind(' ', std::min(hierarchy.find('<'),
hierarchy.find("operator"))));
if (p!=std::string::npos) hierarchy.erase(0, p+1);
// hierarchy.erase
// (hierarchy.find_first_not_of
// ("qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM1234567890_."));
if (hierarchy=="") hierarchy = "global";
std::string name("mrw.fn."+hierarchy);
log4cxx::Logger* logger
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
if (logger->isDebugEnabled()) {
std::basic_ostringstream<log4cxx::String::value_type> ss;
ss<<std::setw(2+--mrw::info.level)
<<std::setfill(log4cxx::String::value_type(' '))
<<"/ "<<log4cxx::String(pos.function.begin(), pos.function.end());
logger->forcedLog(MRW_LEVEL_DEBUG, ss.str(),
MRW_LOG4CXX_LOCATION);
}
}
} catch (...) {}
}
//@}
//@}

View File

@@ -1,133 +0,0 @@
/** @file
$Id: autofunctiontracelog4cxx.cxx,v 1.3 2005/04/14 19:12:18 marc Exp $
$Date: 2005/04/14 19:12:18 $
$Author: marc $
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#ifndef __GNUG__
#error GNU C++ Compiler is required for automatical function trace
#endif
#include <mrw/string.hxx>
#include <mrw/stacktrace.hxx>
#include <iostream>
#include <iomanip>
#if (__GNUC__==3 && __GNUC_MINOR__<4 || __GNUC__<3) \
&& defined(_REENTRANT) && !defined(_MT)
#define _MT
#endif
// these are special built in functions of GNU Compiler Collection
extern "C" void __cyg_profile_func_enter (void *, void *) __attribute__((no_instrument_function));
extern "C" void __cyg_profile_func_exit (void *, void *) __attribute__((no_instrument_function));
namespace mrw {
// workaround doxygen problem:
// - the C++ compiler compiles the following code
// - doxygen ignores it
#ifndef LET_DOXYGEN_IGNORE_THIS // no matching class member found for
// int mrw::ThreadInfo::level()
struct ThreadInfo {
int level;
bool recurse;
};
#endif
#ifdef _MT
static __thread ThreadInfo info = {0, false};
#else
static ThreadInfo info = {0, false};
#endif
static bool mainPassed(false);
class Lock {
public:
Lock() __attribute__((no_instrument_function));
~Lock() __attribute__((no_instrument_function));
};
// workaround doxygen problem:
// - the C++ compiler compiles the following code
// - doxygen ignores it
#ifndef LET_DOXYGEN_IGNORE_THIS // doxygen can't match with __attribute__ above
Lock::Lock() {
info.recurse = true;
}
Lock::~Lock() {
info.recurse = false;
}
#endif
}
extern "C" int main(int, char**);
/** @addtogroup FunctionTrace */
//@{
/** @defgroup AutoFunctionTraceStdlog Automatic Function Trace to standard out for GNU g++
Same as @ref AutoFunctionTrace, but traces to @c stdlog.
If you link to the library @c libmrwautofunctiontracestdlog using
a linker option such as: @c -lmrwautofunctiontracestdlog and you
must enable the GNU Compiler Collection specific function trace
feature with compile and link option @c -finstrument-functions
then you get an automatical function trace, that traces to @c
stdlog. You don't need to change a single line in your code!
*/
//@{
//@}
//@}
extern "C" void __cyg_profile_func_enter(void *this_fn, void*) {
if (!mrw::mainPassed)
if (this_fn == (void*)&::main) // not ANSI C++ conform...
mrw::mainPassed=true;
else
return;
try {
if (mrw::info.recurse) return;
mrw::Lock lock;
{
static bool init(mrw::StackTrace::createSymtable());
if (!init) return;
mrw::StackTrace::CodePos pos(mrw::StackTrace::translate(this_fn));
std::clog<<std::setw(2+mrw::info.level++)<<std::setfill(' ')
<<"\\ "<<pos.function<<" ("<<pos.file<<':'<<pos.line<<')'
<<std::endl;
}
} catch (...) {}
}
extern "C" void __cyg_profile_func_exit(void *this_fn, void*) {
if (!mrw::mainPassed)
return;
else
if (this_fn == (void*)&::main) { // not ANSI C++ conform...
mrw::mainPassed=false;
return;
}
try {
if (mrw::info.recurse || mrw::info.level==0) return;
mrw::Lock lock;
{
mrw::StackTrace::CodePos pos(mrw::StackTrace::translate(this_fn));
std::clog<<std::setw(2+--mrw::info.level)<<std::setfill(' ')
<<"/ "<<pos.function<<" ("<<pos.file<<':'<<pos.line<<')'
<<std::endl;
}
} catch (...) {}
}

View File

@@ -1,250 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
*/
#include <mrw/stacktrace.hxx>
#include <mrw/exception.hxx>
#include <csignal>
#include <exception>
#include <log4cxx/logger.h>
// support for log4cxx 0.9.7 and for new CVS version
#ifndef LOG4CXX_LOCATION
# define MRW_LOG4CXX_LOCATION __FILE__, __LINE__
#define MRW_LEVEL_DEBUG ::log4cxx::Level::DEBUG
#define MRW_LEVEL_INFO ::log4cxx::Level::INFO
#define MRW_LEVEL_WARN ::log4cxx::Level::WARN
#define MRW_LEVEL_ERROR ::log4cxx::Level::ERROR
#define MRW_LEVEL_FATAL ::log4cxx::Level::FATAL
#else
# define LOG4CXX_CVS
# define MRW_LOG4CXX_LOCATION \
::log4cxx::spi::LocationInfo(__FILE__, __FUNCTION__, __LINE__)
#define MRW_LEVEL_DEBUG ::log4cxx::Level::getDebug()
#define MRW_LEVEL_INFO ::log4cxx::Level::getInfo()
#define MRW_LEVEL_WARN ::log4cxx::Level::getWarn()
#define MRW_LEVEL_ERROR ::log4cxx::Level::getError()
#define MRW_LEVEL_FATAL ::log4cxx::Level::getFatal()
#endif
namespace mrw {
/** @addtogroup AutoTrace
@section trclog4cxx Trace using the log4cxx Library
If you link to the library @c libmrwexclog4cxx using a linker
option such as: @c -lmrwexclog4cxx, then an unexpected and a
terminate handler are registered, that trace a fatal error using
the log4cxx library. Also for all know signals there's a signal
handler to trace the stack before termination (except in case of
a @c SIGTRAP, wehere the program is not terminated). You don't
need to change a single line in your code!
The log4cxx library is located at:
- http://logging.apache.org/log4cxx
@note The configurator is not installed automatically. If you
want to trace e.g. on the console, you have to call @c
log4cxx::BasicConfigurator::configure(); as first statement in
your @c main(). @see @ref AutoInitLog4cxx if you also want to
automatically configure @c log4cxx.
*/
//@{
/** @brief unexpected handler, that traces using log4cxx
The unexpected handler is installed automatically when you link
to @c -lmrwexclog4cxx. The implementation of this unexpected
handler is as follows:
@code
void unexpected_log4cxx() {
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("mrw.stacktrace"));
logger->fatal("Unexpected Exception", __FILE__, __LINE__);
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
try {
throw;
} catch (const mrw::exception& x) {
logger->fatal(std::string("Reason:\n")+x.what()
+"\nStack:+\n"+x.stacktrace());
} catch (const std::exception& x) {
logger->fatal(std::string("Reason:\n")+x.what()
+"\nStack:\n"+st);
} catch (...) {
logger->fatal(std::string("Reason: **** not available ****")
+"\nStack:\n"+st);
}
throw std::bad_exception();
}
@endcode
*/
void unexpected_log4cxx() {
static const std::string name("mrw.stacktrace");
log4cxx::LoggerPtr logger
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
static const std::string txt("Unexpected Exception");
logger->fatal(log4cxx::String(txt.begin(), txt.end()), MRW_LOG4CXX_LOCATION);
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
try {
throw;
} catch (const mrw::exception& x) {
std::string txt(std::string("Reason:\n")+x.what()
+"\nStack:\n"+x.stacktrace());
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
} catch (const std::exception& x) {
std::string txt(std::string("Reason:\n")+x.what()
+"\nStack:\n"+st);
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
} catch (...) {
std::string txt(std::string("Reason: **** not available ****")
+"\nStack:\n"+st);
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
}
throw std::bad_exception();
}
/** @brief terminate handler, that traces using log4cxx
The terminate handler is installed automatically when you link
to @c -lmrwexclog4cxx. The implementation of this terminate
handler is as follows:
@code
void terminate_log4cxx() {
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("mrw.stacktrace"));
logger->fatal("Uncaught Exception", __FILE__, __LINE__);
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
try {
throw;
exit(0);
} catch (const mrw::exception& x) {
logger->fatal(std::string("Reason:\n")+x.what()
+"\nStack:+\n"+x.stacktrace());
} catch (const std::exception& x) {
logger->fatal(std::string("Reason:\n")+x.what()
+"\nStack:\n"+st);
} catch (...) {
logger->fatal(std::string("Reason: **** not available ****")
+"\nStack:\n"+st);
}
exit(1);
}
@endcode
*/
void terminate_log4cxx() {
static const std::string name("mrw.stacktrace");
log4cxx::LoggerPtr logger
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
static const std::string txt("Uncaught Exception");
logger->fatal(log4cxx::String(txt.begin(), txt.end()), MRW_LOG4CXX_LOCATION);
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
try {
throw;
} catch (const mrw::exception& x) {
std::string txt(std::string("Reason:\n")+x.what()
+"\nStack:\n"+x.stacktrace());
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
} catch (const std::exception& x) {
std::string txt(std::string("Reason:\n")+x.what()
+"\nStack:\n"+st);
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
} catch (...) {
std::string txt(std::string("Reason: **** not available ****")
+"\nStack:\n"+st);
logger->fatal(log4cxx::String(txt.begin(), txt.end()));
}
exit(1);
}
/** @brief segmentation-fault handler, that traces using log4cxx
The segmentation-fault handler is installed automatically when you link
to @c -lmrwexclog4cxx. The implementation of this handler is as follows:
@code
void signal_log4cxx(int sig) {
std::string txt;
bool abort(true);
switch sig {
case SIGFPE: txt="SIGFPE: Arithmetic error."; break;
case SIGILL: txt="SIGILL: Illegal instruction."; break;
case SIGSEGV: txt="SIGSEGV: Segmentation fault"
" (invalid access to valid memory)."; break;
case SIGBUS: txt="SIGBUS: Invalid pointer dereference"
" (access to an invalid memory address)."; break;
case SIGABRT: txt="SIGABRT: Funktion 'abort' was called."; break;
case SIGIOT: txt="SIGIOT: PDP-11 'iot' instruction"; break;
case SIGTRAP: txt="SIGTRAP: Breakpoint instruction."; abort=false; break;
case SIGEMT: txt="SIGEMT: Emulator trap."; break;
case SIGSYS: txt="SIGSYS: Bad system call."; break;
default: txt="Unknown Signal Nr. "+sig; break;
}
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("mrw.stacktrace"));
logger->fatal("Aborted by signal: "+txt+"\nStack:\n"+st);
if (abort) exit(1);
}
@endcode
*/
void signal_log4cxx(int sig) {
std::string txt;
bool abort(true);
switch (sig) {
case SIGFPE: txt="SIGFPE: Arithmetic error."; break;
case SIGILL: txt="SIGILL: Illegal instruction."; break;
case SIGSEGV: txt="SIGSEGV: Segmentation fault"
" (invalid access to valid memory)."; break;
case SIGBUS: txt="SIGBUS: Invalid pointer dereference"
" (access to an invalid memory address)."; break;
case SIGABRT: txt="SIGABRT: Funktion 'abort' was called."; break;
case SIGTRAP: txt="SIGTRAP: Breakpoint instruction."; abort=false; break;
case SIGSYS: txt="SIGSYS: Bad system call."; break;
default: txt="Unknown Signal Nr. "+sig; break;
}
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
static const std::string name("mrw.stacktrace");
log4cxx::LoggerPtr logger
(log4cxx::Logger::getLogger(log4cxx::String(name.begin(), name.end())));
std::string errtxt("Aborted by signal: "+txt+"\nStack:\n"+st);
logger->fatal(log4cxx::String(errtxt.begin(), errtxt.end()));
if (abort) exit(1);
}
class AutoStackTrace {
public:
AutoStackTrace() {
std::set_unexpected(&mrw::unexpected_log4cxx);
std::set_terminate(&mrw::terminate_log4cxx);
std::signal(SIGFPE, &mrw::signal_log4cxx);
std::signal(SIGILL, &mrw::signal_log4cxx);
std::signal(SIGSEGV, &mrw::signal_log4cxx);
std::signal(SIGBUS, &mrw::signal_log4cxx);
std::signal(SIGTRAP, &mrw::signal_log4cxx);
std::signal(SIGSYS, &mrw::signal_log4cxx);
}
};
//@}
// initialize stack traces (load symbols)
static AutoStackTrace _autoStackTrace;
}

View File

@@ -1,251 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
*/
#include <mrw/stacktrace.hxx>
#include <mrw/exception.hxx>
#include <csignal>
#include <exception>
#include <iostream>
namespace mrw {
/** @addtogroup grpStackTrace */
//@{
/** @defgroup AutoTrace Automated Unexpected and Terminate Handler
with Stack Trace
@brief Don't care about the unexpected handler, don't care about
a try-catch in the main, let the library do all the repetitive
work for you.
For all your programs it is recommended to implement an
identical unexpected handler, that rethrows, catches the @c
mrw::exception, @c std::exception and all unknown exceptions,
traces them and finally quits with a throw of a @c
std::bad_exception. You are also required to write a @c try @c
catch block around all in your @c main, so that you don't miss
any exception. The only thing that may be different from project
to project is, how tracing is done. The MRW C++ Class Library
provides you with additional libraries you can link to. By
linking to the library, you get an unexpected handler and an
exception trace in the @c main for free: You don't need to add a
single line of code, just link to one more library! The
libraries differ in how tracing is done.
The Implementation is done with a static instance of a class that
sets the unexpected handler in the constructor.
@section trcstderr Trace using std::cerr
If you link to the library @c libmrwexcstderr using a linker
option such as: @c -lmrwexcstderr, then an unexpected and a
terminate handler are registered, that trace to the standard
error stream @c std::cerr. Also for all know signals there's a
signal handler to trace the stack before termination (except in
case of a @c SIGTRAP, wehere the program is not terminated). You
don't need to change a single line in your code!
*/
//@{
/** @brief unexpected handler, that traces to @c std::cerr
The unexpected handler is installed automatically when you link
to @c -lmrwexcstderr. The implementation of this unexpected
handler is as follows:
@code
void unexpected_stderr() {
std::cerr<<"UNEXPECTED EXCEPTION: ----------------------------"<<std::endl;
try {
StackTrace::createSymtable();
throw;
} catch (const mrw::exception& x) {
std::cerr<<"---------- Reason:"<<std::endl
<<x.what()<<std::endl
<<"---------- Stack:"<<std::endl
<<x.stacktrace();
} catch (const std::exception& x) {
std::string st((std::string)StackTrace());
std::cerr<<"---------- Reason:"<<std::endl
<<x.what()<<std::endl
<<"---------- Stack: "<<std::endl<<st;
} catch (...) {
std::string st((std::string)StackTrace());
std::cerr<<"---------- Reason: **** not available ****"<<std::endl
<<"---------- Stack:"<<std::endl<<st;
}
std::cerr<<"-------------------------------------------------"<<std::endl;
throw std::bad_exception();
}
@endcode
*/
void unexpected_stderr() {
std::cerr<<"UNEXPECTED EXCEPTION: ----------------------------"<<std::endl;
try {
StackTrace::createSymtable();
throw;
} catch (const mrw::exception& x) {
std::cerr<<"---------- Reason:"<<std::endl
<<x.what()<<std::endl
<<"---------- Stack:"<<std::endl
<<x.stacktrace();
} catch (const std::exception& x) {
std::string st((std::string)StackTrace());
std::cerr<<"---------- Reason:"<<std::endl
<<x.what()<<std::endl
<<"---------- Stack:"<<std::endl<<st;
} catch (...) {
std::string st((std::string)StackTrace());
std::cerr<<"---------- Reason: **** not available ****"<<std::endl
<<"---------- Stack:"<<std::endl<<st;
}
std::cerr<<"-------------------------------------------------"<<std::endl;
throw std::bad_exception();
}
/** @brief terminate handler, that traces to @c std::cerr
The terminate handler is installed automatically when you link
to @c -lmrwexcstderr. The implementation of this terminate
handler is as follows:
@code
void terminate_stderr() {
std::cerr<<"UNCAUGHT EXCEPTION: ----------------------------"<<std::endl;
try {
throw;
} catch (const mrw::exception& x) {
StackTrace::createSymtable();
std::cerr<<"---------- Reason:"<<std::endl
<<x.what()<<std::endl
<<"---------- Stack:"<<std::endl
<<x.stacktrace();
} catch (const std::exception& x) {
std::cerr<<"---------- Reason:"<<std::endl
<<x.what()<<std::endl
<<"---------- Stack: **** not available ****"<<std::endl;
} catch (...) {
std::cerr<<"---------- Reason: **** not available ****"<<std::endl
<<"---------- Stack: **** not available ****"<<std::endl;
}
std::cerr<<"-------------------------------------------------"<<std::endl;
exit(1);
}
@endcode
*/
void terminate_stderr() {
std::cerr<<"UNCAUGHT EXCEPTION: ----------------------------"<<std::endl;
try {
throw;
} catch (const mrw::exception& x) {
StackTrace::createSymtable();
std::cerr<<"---------- Reason:"<<std::endl
<<x.what()<<std::endl
<<"---------- Stack:"<<std::endl
<<x.stacktrace();
} catch (const std::exception& x) {
std::cerr<<"---------- Reason:"<<std::endl
<<x.what()<<std::endl
<<"---------- Stack: **** not available ****"<<std::endl;
} catch (...) {
std::cerr<<"---------- Reason: **** not available ****"<<std::endl
<<"---------- Stack: **** not available ****"<<std::endl;
}
std::cerr<<"-------------------------------------------------"<<std::endl;
exit(1);
}
/** @brief segmentation-fault handler, that traces using stderr
The segmentation-fault handler is installed automatically when you link
to @c -lmrwexcstderr. The implementation of this handler is as follows:
@code
void signal_stderr(int sig) {
std::cerr<<"SIGNAL RECEIVED: -------------------------------"<<std::endl;
std::string txt;
bool abort(true);
switch (sig) {
case SIGFPE: txt="SIGFPE: Arithmetic error."; break;
case SIGILL: txt="SIGILL: Illegal instruction."; break;
case SIGSEGV: txt="SIGSEGV: Segmentation fault"
" (invalid access to valid memory)."; break;
case SIGBUS: txt="SIGBUS: Invalid pointer dereference"
" (access to an invalid memory address)."; break;
case SIGABRT: txt="SIGABRT: Funktion 'abort' was called."; break;
case SIGTRAP: txt="SIGTRAP: Breakpoint instruction."; abort=false; break;
case SIGSYS: txt="SIGSYS: Bad system call."; break;
default: txt="Unknown Signal Nr. "+sig; break;
}
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
stderr::LoggerPtr logger(stderr::Logger::getLogger(_T("mrw.stacktrace")));
std::cerr<<"---------- Reason:"<<std::endl
<<"Aborted by signal: "<<txt<<std::endl
<<"---------- Stack:"<<std::endl
<<st<<std::endl
<<"-------------------------------------------------"<<std::endl;
if (abort) exit(1);
}
@endcode
*/
void signal_stderr(int sig) {
std::cerr<<"SIGNAL RECEIVED: -------------------------------"<<std::endl;
std::string txt;
bool abort(true);
switch (sig) {
case SIGFPE: txt="SIGFPE: Arithmetic error."; break;
case SIGILL: txt="SIGILL: Illegal instruction."; break;
case SIGSEGV: txt="SIGSEGV: Segmentation fault"
" (invalid access to valid memory)."; break;
case SIGBUS: txt="SIGBUS: Invalid pointer dereference"
" (access to an invalid memory address)."; break;
case SIGABRT: txt="SIGABRT: Funktion 'abort' was called."; break;
case SIGTRAP: txt="SIGTRAP: Breakpoint instruction."; abort=false; break;
case SIGSYS: txt="SIGSYS: Bad system call."; break;
default: txt="Unknown Signal Nr. "+sig; break;
}
StackTrace::createSymtable();
std::string st((std::string)StackTrace());
std::cerr<<"---------- Reason:"<<std::endl
<<"Aborted by signal: "<<txt<<std::endl
<<"---------- Stack:"<<std::endl
<<st<<std::endl
<<"-------------------------------------------------"<<std::endl;
if (abort) exit(1);
}
//@}
//@}
class AutoStackTrace {
public:
AutoStackTrace() {
std::set_unexpected(&mrw::unexpected_stderr);
std::set_terminate(&mrw::terminate_stderr);
std::signal(SIGFPE, &mrw::signal_stderr);
std::signal(SIGILL, &mrw::signal_stderr);
std::signal(SIGSEGV, &mrw::signal_stderr);
std::signal(SIGBUS, &mrw::signal_stderr);
std::signal(SIGIOT, &mrw::signal_stderr);
std::signal(SIGTRAP, &mrw::signal_stderr);
std::signal(SIGSYS, &mrw::signal_stderr);
}
};
// initialize stack traces (load symbols)
static AutoStackTrace _autoStackTrace;
}

View File

@@ -1,193 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.3 2005/11/29 12:39:42 marc
make it compilable with gcc 4.0.2 and newer doxygen
Revision 1.2 2005/01/28 07:49:32 marc
Save configuration using file.hxx
Revision 1.1 2005/01/07 00:31:38 marc
initial version
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#include <mrw/configfile.hxx>
#include <mrw/exception.hxx>
#include <mrw/string.hxx>
#include <mrw/file.hxx>
#include <fstream>
mrw::ConfigFileReader::Value&
mrw::ConfigFileReader::operator()(const std::string& section,
const std::string& name,
const std::string& default_)
throw(std::bad_exception) {
_values[section].insert(std::make_pair(name, Value(default_)));
return _values[section].find(name)->second;
}
mrw::ConfigFileReader& mrw::ConfigFileReader::load(const std::string& filename)
throw(std::exception) {
_filename = filename;
return reload();
}
mrw::ConfigFileReader& mrw::ConfigFileReader::reload() throw(std::exception) {
return parse(mrw::File::read(_filename));
}
mrw::ConfigFileReader& mrw::ConfigFileReader::parse(const std::string& file)
throw(std::exception) {
_values.erase(_values.begin(), _values.end());
std::string section;
for (std::string::size_type pos(0);
(pos=file.find_first_of("[=#", pos))!=std::string::npos; ++pos) {
switch (file[pos]) {
case '[': _sections[section]=pos; section=parseSection(file, pos); break;
case '=': _values[section].insert(parseValue(file, pos)); break;
case '#': parseComment(file, pos); break;
};
}
_sections[section]=file.size();
return *this;
}
std::string mrw::ConfigFileReader::parseSection(const std::string& file,
std::string::size_type& pos)
const throw(std::exception) {
std::string::size_type start(pos);
if ((pos=file.find(']', pos))==std::string::npos)
throw mrw::invalid_argument
("section not terminated in file '"+_filename+"'\n"
"environment is: "+file.substr(start-10>0?start-10:0));
return file.substr(start+1, pos-start-1);
}
mrw::ConfigFileReader::Values::mapped_type::value_type
mrw::ConfigFileReader::parseValue(const std::string& file,
std::string::size_type& pos)
const throw(std::exception) {
// find the begin of the variable name
std::string::size_type startName(file.rfind('\n', pos));
if (startName==std::string::npos) startName=0;
startName=file.find_first_not_of("\n\t ", startName);
if (startName==pos)
throw mrw::invalid_argument
("empty variable name in file '"+_filename+"'\n"
"environment is: "+file.substr(startName-10>0?startName-10:0, pos+10));
// find the end of the variable name
std::string::size_type endName(file.find_last_not_of("\n\t ", pos-1)+1);
// find the begin of the variable contents
std::string::size_type startVal(file.find_first_not_of("\n\t ", ++pos));
if (startVal==std::string::npos)
return std::make_pair // end of file, empty value
(file.substr(startName, endName-startName), Value("", pos, pos));
// find the end of the variable contents
std::string::size_type realStart(startVal); // doesn't cut the first quote
std::string::size_type endVal(file[startVal]=='"' ? // quoted with "
file.find('"', ++startVal) :
file[startVal]=='\'' ? // quoted with '
file.find('\'', ++startVal) :
file.find_first_of("[=#", startVal)); // normal
if (endVal!=std::string::npos && file[endVal]=='=')
endVal=file.rfind('\n', endVal); // jump before following variable name
endVal = file.find_last_not_of("\n\t ", // remove trailing white spaces
endVal!=std::string::npos?endVal-1:endVal)+1;
std::string::size_type realEnd(endVal!=std::string::npos && // quotes?
(file[realStart]=='"' && file[endVal]=='"' ||
file[realStart]=='\'' && file[endVal]=='\'')
? endVal+1 : endVal);
if (endVal<=startVal)
return std::make_pair // empty value
(file.substr(startName, endName-startName), Value("", pos, pos));
return std::make_pair // normal case
(file.substr(startName, endName-startName),
Value(file.substr(startVal, endVal-startVal), realStart, pos=realEnd));
}
std::string mrw::ConfigFileReader::parseComment(const std::string& file,
std::string::size_type& pos)
const throw(std::bad_exception) {
std::string::size_type start(pos);
pos = file.find('\n', pos);
return file.substr(start, pos-start);
}
// GNU g++ prior to 3.4 does not implement covariant returns
#if __GNUC__ == 3 && __GNUC_MINOR__ < 4
mrw::ConfigFileReader&
#else
mrw::ConfigFileWriter&
#endif
mrw::ConfigFileWriter::reload() throw(std::exception) {
#if __GNUC__ == 3 && __GNUC_MINOR__ < 4
return parse(_file=mrw::File::read(_filename));
#else
return dynamic_cast<mrw::ConfigFileWriter&>
(parse(_file=mrw::File::read(_filename)));
#endif
}
mrw::ConfigFileWriter& mrw::ConfigFileWriter::save() throw(std::exception) {
if (_filename=="") return *this;
// work in changes
bool changed(false);
for (Values::iterator sec(_values.begin()); sec!=_values.end(); ++sec)
for (Values::mapped_type::iterator var(sec->second.begin());
var!=sec->second.end(); ++var)
if (var->second.changed) {
var->second.changed = false;
changed = true;
// check if we need quoting
std::string value(var->second.value);
if (value.find_first_of("[=#")!=std::string::npos)
if (value.find('"')==std::string::npos)
value = '"'+value+'"';
else if (value.find('\'')==std::string::npos)
value = '\''+value+'\'';
else
throw mrw::invalid_argument("Configuration value is not quotable: "
+value);
// recalculate all positions
if (var->second.start &&
value.size() != var->second.end-var->second.start) {
int diff(value.size()-var->second.end+var->second.start);
for (Values::iterator sec2(_values.begin());
sec2!=_values.end(); ++sec2)
for (Values::mapped_type::iterator var2(sec2->second.begin());
var2!=sec2->second.end(); ++var2)
if (var2->second.start>var->second.end) {
var2->second.start += diff;
var2->second.end += diff;
}
for (Sections::iterator sec2(_sections.begin());
sec2!=_sections.end(); ++sec2)
if (sec2->second>=var->second.end) sec2->second += diff;
}
// set the new value
if (var->second.start) // simple change
_file.replace(var->second.start, var->second.end-var->second.start,
value);
else if (_sections.find(sec->first)!=_sections.end()) // new value
_file.insert(_sections[sec->first], "\n"+var->first+" = "+value
+(_file[_sections[sec->first]]=='\n'?"":"\n"));
else { // even a new section
_file+="\n["+sec->first+"]\n"+var->first+" = "+value;
_sections[sec->first] = _file.size();
}
}
if (changed) mrw::File::save(_filename, _file);
return *this;
}

View File

@@ -1,4 +0,0 @@
#! /bin/bash
test -z "`diff $srcdir/configfile2.ini $srcdir/configfile.ini.result`" \
&& rm configfile2.ini

View File

@@ -1,72 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.2 2005/04/07 20:55:21 marc
Oops, there's a make distcheck...? Now it works.
Revision 1.1 2005/01/07 00:31:38 marc
initial version
*/
#include <mrw/configfile.hxx>
#include <mrw/file.hxx>
#include <mrw/stdext.hxx> // ifelse
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <stdlib.h> // getenv
class ConfigFileTest: public CppUnit::TestFixture {
public:
void CheckFile() {
std::string srcdir(mrw::ifelse(getenv("srcdir"), "."));
mrw::File::copy(srcdir+"/configfile.ini", "configfile2.ini");
mrw::ConfigFileWriter config("configfile2.ini");
CPPUNIT_ASSERT(config("", "xxx", ".")=="yyy");
CPPUNIT_ASSERT(config("Section", "abc", ".")=="");
CPPUNIT_ASSERT(config("Section", "def", ".")=="hallo welt");
CPPUNIT_ASSERT(config("Section", "ghi", ".")=="");
CPPUNIT_ASSERT(config("Section", "jkl", ".")=="mn\n op qr\n st");
CPPUNIT_ASSERT(config("Other Section", "1234", ".")=="5678=90");
CPPUNIT_ASSERT(config("Other Section", "here we are", ".")
=="some contents");
CPPUNIT_ASSERT(config("Other Section", "here", ".")=="");
config("", "xxx", ".")="0";
config("Section", "abc", ".")="1";
CPPUNIT_ASSERT(config("New Section", "a first one", "sgadd")=="sgadd");
config("Section", "def", ".")="Und=Tschuess";
config("Section", "ghi", ".")="3";
config("Section", "jkl", ".")="4";
config("Other Section", "1234", ".")="5";
config("Other Section", "here we are", ".")="6";
config("Other Section", "here", ".")="7";
CPPUNIT_ASSERT(config("Other Section", "no no", ".")==".");
CPPUNIT_ASSERT(config("Other Section", "no no no", ".")==".");
CPPUNIT_ASSERT(config("Other Section", "yes", ".")==".");
CPPUNIT_ASSERT(config("Section", "guguseli", "dadaa")=="dadaa");
CPPUNIT_ASSERT(config("Section", "guguseli zwei", "dadaa")=="dadaa");
CPPUNIT_ASSERT(config("Section", "guguseli drei", "dadaa")=="dadaa");
CPPUNIT_ASSERT(config("New Section", "one more", ".")==".");
}
CPPUNIT_TEST_SUITE(ConfigFileTest);
CPPUNIT_TEST(CheckFile);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(ConfigFileTest);
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,47 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.1 2005/02/18 15:53:56 marc
initial release
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#include <mrw/dynamiclibrary.hxx>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
class DynamicLibraryTest: public CppUnit::TestFixture {
public:
void Load() {
mrw::DynamicLibrary lib("libdynamiclibrary_testlib");
int(*test1)(int) = (int(*)(int))lib.symbol("test1");
CPPUNIT_ASSERT((*test1)(2)==4);
}
void LoadError() {
mrw::DynamicLibrary lib("DASist-Sicher_Keine_DynamischePHIPLIOTEEK!!!");
}
CPPUNIT_TEST_SUITE(DynamicLibraryTest);
CPPUNIT_TEST(Load);
CPPUNIT_TEST_EXCEPTION(LoadError, mrw::DynamicLibrary::failure);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(DynamicLibraryTest);
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,24 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.1 2005/02/18 15:53:55 marc
initial release
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
extern "C" {
int test1(int i) {
return i*i;
}
}

View File

@@ -1,61 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.3 2005/02/28 07:29:18 marc
added ifdef for non glibc (Solaris)
Revision 1.2 2005/02/18 15:53:07 marc
I'm so stupid, there's strerror for mapping errno to a string...
Revision 1.1 2005/02/08 12:30:22 marc
new in release 1.8.0
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#include <mrw/errno.hxx>
#include <mrw/string.hxx>
#include <mrw/stdext.hxx>
#include <errno.h>
#include <string.h>
mrw::Errno::Errno() throw(): _errnoxxx(errno) {}
mrw::Errno::operator std::string() const throw(std::bad_exception) {
return *this;
}
std::string mrw::Errno::string() const throw(std::bad_exception) {
char* pos(0);
char error[1024];
#ifdef __GLIBC__
# if defined __USE_XOPEN2K && !defined __USE_GNU
return strerror_r(errno=_errnoxxx, error, 1024)!=-1
? error+std::string(" errno=")+_errnoxxx
: std::string("errno=")+_errnoxxx;
# else
return (pos=strerror_r(errno=_errnoxxx, error, 1024))
? pos+std::string(" errno=")+_errnoxxx
: std::string("errno=")+_errnoxxx;
# endif
#else
# if defined __USE_XOPEN2K && !defined __USE_GNU
return strerror_r(errno=_errnoxxx, error, 1024)!=-1
? error+std::string(" errno=")+_errnoxxx
: std::string("errno=")+_errnoxxx;
# else
return (pos=strerror(errno=_errnoxxx))
? error+std::string(" errno=")+_errnoxxx
: std::string("errno=")+_errnoxxx;
# endif
#endif
}

View File

@@ -1,50 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.2 2004/08/28 16:21:25 marc
mrw-c++-0.92 (mrw)
- new file: version.cxx
- new file header for all sources
- work around warning in mrw::auto<T>
- possibility to compile without log4cxx
- work around bugs in demangle.h and libiberty.h
- corrections in documentation
- added simple tracing mechanism
- more warnings
- small corrections in Auto<>::Free and a new test for it
- possibility to compile without stack trace
*/
#include <mrw/exception.hxx>
#ifdef HAVE_STACKTRACE
# include <mrw/stacktrace.hxx>
#else
namespace mrw {
class StackTrace {
public:
operator std::string() throw() {return "";}
};
}
#endif
namespace mrw {
exception::exception() throw(std::bad_exception):
_stacktrace(new StackTrace) {
}
exception::~exception() throw() {
delete _stacktrace;
}
const std::string& exception::stacktrace() const throw(std::bad_exception) {
static const std::string st(*_stacktrace);
return st;
}
}

View File

@@ -1,557 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.14 2005/11/29 12:39:42 marc
make it compilable with gcc 4.0.2 and newer doxygen
Revision 1.13 2005/04/20 18:32:14 marc
*** empty log message ***
Revision 1.12 2005/04/20 18:12:55 marc
added kill() for PartialExec
Revision 1.11 2005/04/19 18:48:00 marc
new feature PartialExec
Revision 1.10 2005/03/14 16:26:34 marc
bugs have been fixed a long time ago, now no more in buglist
Revision 1.9 2004/12/20 07:40:35 marc
documentation improved, new grouping
Revision 1.8 2004/12/18 21:00:09 marc
everything is ok, when pipes are non blocking on parent's side and blocking on client's side, and select is not used (not necessary for non blocking IO)
Revision 1.7 2004/12/17 17:38:57 marc
it works perfectly with blocking pipes and buffer size of 1
Revision 1.6 2004/12/17 16:28:51 marc
stable implementation with select for both executes
Revision 1.5 2004/12/14 20:30:09 marc
added possibility to pass string to stdin of child process
Revision 1.4 2004/08/28 16:21:25 marc
mrw-c++-0.92 (mrw)
- new file: version.cxx
- new file header for all sources
- work around warning in mrw::auto<T>
- possibility to compile without log4cxx
- work around bugs in demangle.h and libiberty.h
- corrections in documentation
- added simple tracing mechanism
- more warnings
- small corrections in Auto<>::Free and a new test for it
- possibility to compile without stack trace
*/
#include <mrw/exec.hxx>
#include <mrw/unistd.hxx>
#include <mrw/exception.hxx>
#include <sys/wait.h> // waitpid
#include <unistd.h> // fork, exec
#include <string.h> // memcpy
#include <assert.h> // assert
#include <sys/types.h> // kill
#include <signal.h> // kill
#include <cstdlib> // exit
//=========================================================== ExecutionFailedExc
//------------------------------------------------------------------------------
mrw::ExecutionFailedExc::ExecutionFailedExc(const std::string& w,
const std::string& c)
throw(std::bad_exception):
_what(std::string("mrw::Exec: command execution failed\n")+
std::string(" failed command was: \""+c+"\"\n")+
std::string(" error was: \"")+w+'"') {
/**
@c what looks like:
@verbatim
mrw::Exec: command execution failed
failed command was: "/bin/OOOOPS -v -q --crash"
error was: "execution failed"
@endverbatim
*/
}
//========================================================================== Cmd
//------------------------------------------------------------------------------
mrw::Cmd::Cmd(const std::string& c) throw(std::bad_exception) {
_cmd.push_back(c);
}
//------------------------------------------------------------------------------
mrw::Cmd& mrw::Cmd::operator,(const std::string& arg)
throw(std::bad_exception) {
_cmd.push_back(arg);
return *this;
}
//------------------------------------------------------------------------------
mrw::Cmd& mrw::Cmd::operator<<(const std::string& arg)
throw(std::bad_exception) {
_cmd.push_back(arg);
return *this;
}
//------------------------------------------------------------------------------
mrw::Cmd::operator std::string() const throw(std::bad_exception) {
ArgList::const_iterator it(_cmd.begin());
std::string c(*it);
while (++it!=_cmd.end()) c+=' '+*it;
return c;
}
//------------------------------------------------------------------------------
mrw::Cmd::operator mrw::Exec() const throw(std::bad_exception) {
return mrw::Exec(*this);
}
//------------------------------------------------------------------------------
mrw::Cmd::operator mrw::PartialExec() const throw(std::bad_exception) {
return mrw::PartialExec(*this);
}
//------------------------------------------------------------------------------
mrw::Exec mrw::Cmd::execute(bool exc) const throw(std::exception) {
return mrw::Exec(*this).execute(exc);
}
//------------------------------------------------------------------------------
mrw::Exec mrw::Cmd::execute(const std::string& input, bool exc) const
throw(std::exception) {
return mrw::Exec(*this).execute(input, exc);
}
//------------------------------------------------------------------------------
mrw::PartialExec mrw::Cmd::start(bool useInput) const throw(std::exception) {
return mrw::PartialExec(*this).start(useInput);
}
//------------------------------------------------------------------------------
const char* mrw::Cmd::path() const throw(std::bad_exception) {
return _cmd.front().c_str();
}
//------------------------------------------------------------------------------
char** mrw::Cmd::args() const throw(std::bad_exception) {
if (_cmd.size()==0) return 0;
char** array = new char*[_cmd.size()+1];
int i(0);
for (ArgList::const_iterator it(_cmd.begin()); it!=_cmd.end(); ++it)
memcpy(array[i++]=new char[it->size()+1], it->c_str(), it->size()+1);
array[i] = 0;
return array;
}
//========================================================================= Exec
//------------------------------------------------------------------------------
mrw::Exec::Exec(const mrw::Cmd& c) throw(std::bad_exception):
_cmd(new mrw::Cmd(c)), _success(false) {
}
//------------------------------------------------------------------------------
mrw::Exec::Exec(const mrw::Exec& e) throw(std::bad_exception):
_cmd(new mrw::Cmd(*e._cmd)),
_res(e._res), _err(e._err), _success(e._success) {
}
//------------------------------------------------------------------------------
mrw::Exec::~Exec() throw() {
delete _cmd;
}
//------------------------------------------------------------------------------
mrw::Exec& mrw::Exec::operator=(const mrw::Exec& e) throw(std::bad_exception) {
if (this==&e) return *this;
*_cmd=*e._cmd; _res=e._res; _err=e._err; _success=e._success;
return *this;
}
//------------------------------------------------------------------------------
mrw::Exec& mrw::Exec::execute(bool exc) throw(std::exception) {
/** This method calls @c fork, sets up a pipe connection to pass @c
stdout and @c stderr from the child process to the parent
process using mrw::Pipe and calls @c execvp to execute the
program. */
_success = false;
_res = _err = "";
mrw::Pipe stdOut(mrw::Pipe::block_output), stdErr(mrw::Pipe::block_output);
if (!stdOut || !stdErr)
throw mrw::ExecutionFailedExc("cannot create pipe", *_cmd);
pid_t pid(fork());
if (pid<0)
throw ExecutionFailedExc("cannot fork", *_cmd);
if (pid) { // parent
stdOut.close_out();
stdErr.close_out();
if (!stdOut || !stdErr)
throw ExecutionFailedExc("cannot close pipe", *_cmd);
ssize_t num1(1), num2(1);
char buf[4096];
int res(0), s(0);
/* It sometimes did not get the whole input since I changed to non
blocking pipes. Now I have found the solution to the problems:
Non blocking IO does not work in conjunction with select!
Also the pipe must not be nonblocking on both ends, but only on
one. */
while (num1||num2||!res) try { // not end of files or child terminated
if (!res && (res=waitpid(pid, &s, WNOHANG)))
if (res!=pid || WIFEXITED(s)!=0 && WEXITSTATUS(s)!=0)
throw ExecutionFailedExc("execution failed", *_cmd);
if (num1<=0&&num2<=0) usleep(10000); // nothing to read last time
// check and handle stdout
if (num1 && (num1=read(stdOut.istream(), buf, sizeof(buf)))>0)
_res += std::string(buf, num1);
else if (num1==-1)
if (errno!=EINTR&&errno!=EAGAIN)
throw ExecutionFailedExc("readin stdout", *_cmd);
else
num1 = 1;
// check and handle stderr
if (num2 && (num2=read(stdErr.istream(), buf, sizeof(buf)))>0)
_err += std::string(buf, num2);
else if (num2==-1)
if (errno!=EINTR&&errno!=EAGAIN)
throw ExecutionFailedExc("readin stderr", *_cmd);
else
num2 = 1;
} catch (...) {
_success = false;
if (exc) throw;
return *this;
}
} else { // child
stdOut.close_in();
stdErr.close_in();
stdOut.connect_cout();
stdErr.connect_cerr();
execvp(_cmd->path(), _cmd->args());
exit(1); // execute failed
}
_success = true;
return *this;
}
//------------------------------------------------------------------------------
mrw::Exec& mrw::Exec::execute(const std::string& input, bool exc)
throw(std::exception) {
#ifdef SSIZE_MAX
/// @c input length must be smaller than @c SSIZE_MAX.
/// I'll only add support for longer strings upon request.
assert(input.size()<=SSIZE_MAX &&
"sdin input exeeds C library limit in mrw::Exec "
"please contact the author of the library");
#endif
/** This method calls @c fork, sets up a pipe connection to pass @c
stdin, @c stdout and @c stderr between the child process and the
parent process using mrw::Pipe and calls @c execvp to execute
the program. */
_success = false;
_res = _err = "";
mrw::Pipe stdIn(mrw::Pipe::block_input),
stdOut(mrw::Pipe::block_output), stdErr(mrw::Pipe::block_output);
if (!stdIn || !stdOut || !stdErr)
throw mrw::ExecutionFailedExc("cannot create pipe", *_cmd);
pid_t pid(fork());
if (pid<0) throw ExecutionFailedExc("cannot fork", *_cmd);
if (pid) { // parent
stdIn.close_in();
stdOut.close_out();
stdErr.close_out();
if (!stdIn || !stdOut || !stdErr)
throw ExecutionFailedExc("cannot close pipes", *_cmd);
ssize_t num0(1), num1(1), num2(1);
std::string in(input);
char buf[4096];
int res(0), s(0);
/* It sometimes did not get the whole input since I changed to non
blocking pipes. Now I have found the solution to the problems:
Non blocking IO does not work in conjunction with select! Also
the pipe must not be nonblocking on both ends, but only on
one. */
while (num0||num1||num2||!res) try { // not end of files or child terminated
if (!res && (res=waitpid(pid, &s, WNOHANG)))
if (res!=pid || WIFEXITED(s)!=0 && WEXITSTATUS(s)!=0)
throw ExecutionFailedExc("execution failed", *_cmd);
if (num0<=0&&num1<=0&&num2<=0) usleep(10000); // no activity last time
// check and handle stdin
if (num0 && (num0=write(stdIn.ostream(), in.c_str(), in.size()))>0) {
if ((unsigned int)num0<in.size())
in = in.substr(num0);
else if ((unsigned int)num0==in.size())
num0=0, stdIn.close_out();
} else if (num0==-1)
if (errno!=EINTR&&errno!=EAGAIN)
throw ExecutionFailedExc("writing stdin", *_cmd);
else
num0 = 1;
// check and handle stdout
if (num1 && (num1=read(stdOut.istream(), buf, sizeof(buf)))>0)
_res += std::string(buf, num1);
else if (num1==-1)
if (errno!=EINTR&&errno!=EAGAIN)
throw ExecutionFailedExc("readin stdout", *_cmd);
else
num1 = 1;
// check and handle stderr
if (num2 && (num2=read(stdErr.istream(), buf, sizeof(buf)))>0)
_err += std::string(buf, num2);
else if (num2==-1)
if (errno!=EINTR&&errno!=EAGAIN)
throw ExecutionFailedExc("readin stderr", *_cmd);
else
num2 = 1;
} catch (...) {
_success = false;
if (exc) throw;
return *this;
}
} else { // child
stdIn.close_out();
stdOut.close_in();
stdErr.close_in();
stdIn.connect_cin();
stdOut.connect_cout();
stdErr.connect_cerr();
execvp(_cmd->path(), _cmd->args());
exit(1); // execute failed
}
_success = true;
return *this;
}
//------------------------------------------------------------------------------
mrw::Exec& mrw::Exec::operator>>(std::string& res) throw(std::exception) {
execute();
res += _res;
return *this;
}
//------------------------------------------------------------------------------
mrw::Exec::operator std::string&() throw(std::exception) {
if (!_success) execute();
return _res;
}
//------------------------------------------------------------------------------
mrw::Exec::operator bool() throw(std::bad_exception) {
return _success;
}
//------------------------------------------------------------------------------
std::string& mrw::Exec::result() throw(std::exception) {
if (!_success) execute();
return _res;
}
//------------------------------------------------------------------------------
std::string& mrw::Exec::error() throw(std::exception) {
if (!_success) execute();
return _err;
}
//------------------------------------------------------------------------------
bool mrw::Exec::success() throw(std::bad_exception) {
return _success;
}
//================================================================== PartialExec
//------------------------------------------------------------------------------
mrw::PartialExec::PartialExec(const mrw::Cmd& c) throw(std::bad_exception):
Exec(c), _finished(true), _finish(false) {
}
//------------------------------------------------------------------------------
mrw::PartialExec::PartialExec(mrw::PartialExec& e)
throw(std::bad_exception):
Exec(e), _finished(e._finished), _finish(e._finish),
_stdIn(e._stdIn), _stdOut(e._stdOut), _stdErr(e._stdErr), _input(e._input),
_num0(e._num0), _num1(e._num1), _num2(e._num2),
_lastPid(e._lastPid), _pid(e._pid) {
e._finished = true;
}
//------------------------------------------------------------------------------
mrw::PartialExec::PartialExec(const mrw::PartialExec& e)
throw(std::bad_exception):
Exec(e), _finished(e._finished), _finish(e._finish),
_input(e._input),
_num0(e._num0), _num1(e._num1), _num2(e._num2),
_lastPid(e._lastPid), _pid(e._pid) {
/** @warning @c const is casted away */
mrw::PartialExec& nonConstE(const_cast<mrw::PartialExec&>(e));
_stdIn = nonConstE._stdIn;
_stdOut = nonConstE._stdOut;
_stdErr = nonConstE._stdErr;
nonConstE._finished = true;
nonConstE._finish = false;
}
//------------------------------------------------------------------------------
mrw::PartialExec& mrw::PartialExec::operator=(mrw::PartialExec& e)
throw(std::bad_exception) {
if (this==&e) return *this;
*_cmd=*e._cmd; _res=e._res; _err=e._err; _success=e._success;
_finished = e._finished;
_finish = e._finish;
_stdIn = e._stdIn; _stdOut = e._stdOut; _stdErr = e._stdErr;
_input = e._input; _num0 = e._num0; _num1 = e._num1; _num2 = e._num2;
_lastPid = e._lastPid;
_pid = e._pid;
e._finished = true;
e._finish = false;
return *this;
}
//------------------------------------------------------------------------------
mrw::PartialExec& mrw::PartialExec::finish() throw() {
_finish = true;
return *this;
}
//------------------------------------------------------------------------------
bool mrw::PartialExec::finished() throw() {
return _finished;
}
//------------------------------------------------------------------------------
mrw::PartialExec& mrw::PartialExec::start(bool useInput)
throw(std::exception) {
if (!_finished) throw mrw::runtime_error("running process not yet finished");
/** This method calls @c fork, sets up a pipe connection to pass @c
stdin, @c stdout and @c stderr between the child process and the
parent process using mrw::Pipe and calls @c execvp to execute
the program. */
_success = false;
_finish = !useInput;
_input = "";
_res = _err = "";
_stdIn = std::auto_ptr<mrw::Pipe>(new mrw::Pipe(mrw::Pipe::block_input));
_stdOut = std::auto_ptr<mrw::Pipe>(new mrw::Pipe(mrw::Pipe::block_output));
_stdErr = std::auto_ptr<mrw::Pipe>(new mrw::Pipe(mrw::Pipe::block_output));
if (!*_stdIn || !*_stdOut || !*_stdErr)
throw mrw::ExecutionFailedExc("cannot create pipe", *_cmd);
_lastPid = 0;
_pid = fork();
if (_pid<0) throw ExecutionFailedExc("cannot fork", *_cmd);
if (_pid) { // parent
_stdIn->close_in();
_stdOut->close_out();
_stdErr->close_out();
if (!*_stdIn || !*_stdOut || !*_stdErr)
throw ExecutionFailedExc("cannot close pipes", *_cmd);
_num0 = _num1 = _num2 = 1;
_finished = false;
} else { // child
_stdIn->close_out();
_stdOut->close_in();
_stdErr->close_in();
_stdIn->connect_cin();
_stdOut->connect_cout();
_stdErr->connect_cerr();
execvp(_cmd->path(), _cmd->args());
exit(1); // execute failed
}
_success = true;
return *this;
}
//------------------------------------------------------------------------------
std::pair<std::string, std::string>
mrw::PartialExec::read(const std::string& input, bool exc)
throw(std::exception) {
std::pair<std::string, std::string> output;
#ifdef SSIZE_MAX
/** @note @c input length must be smaller than @c SSIZE_MAX.
I'll only add support for longer strings upon request. */
assert(input.size()<=SSIZE_MAX &&
"sdin input exeeds C library limit in mrw::Exec "
"please contact the author of the library");
#endif
/** @warning After calling finish(), it is forbidden to pass
any @c input string, it must then always be empty,
because the pipe is already closed! */
assert(!(_finish && input.size()) &&
"after calling PartialExec::finish(), it is forbidden "
"to pass new input text, because the pipe is already "
"closed! this is a programming but that must be solved!");
_input += input;
/* It sometimes did not get the whole input since I changed to non
blocking pipes. Now I have found the solution to the problems:
Non blocking IO does not work in conjunction with select! Also
the pipe must not be nonblocking on both ends, but only on
one. */
if (!_finished) try { // not finished
char buf[4096];
int s(0);
if (!_lastPid && (_lastPid=waitpid(_pid, &s, WNOHANG))) {
if (_lastPid!=_pid || WIFEXITED(s)!=0 && WEXITSTATUS(s)!=0)
throw ExecutionFailedExc("execution failed", *_cmd);
}
// check and handle stdin
if (_input.size() && _num0!=-1 &&
(_num0=write(_stdIn->ostream(), _input.c_str(), _input.size()))>0) {
if ((unsigned int)_num0<_input.size())
_input = _input.substr(_num0);
else if ((unsigned int)_num0==_input.size())
_input.clear();
} else if (_num0==-1)
if (errno!=EINTR&&errno!=EAGAIN)
throw ExecutionFailedExc("writing stdin", *_cmd);
else
_num0 = 1;
// check and handle stdout
if (_num1 && (_num1=::read(_stdOut->istream(), buf, sizeof(buf)))>0)
_res += output.first=std::string(buf, _num1);
else if (_num1==-1)
if (errno!=EINTR&&errno!=EAGAIN)
throw ExecutionFailedExc("readin stdout", *_cmd);
else
_num1 = 1;
// check and handle stderr
if (_num2 && (_num2=::read(_stdErr->istream(), buf, sizeof(buf)))>0)
_err += output.second=std::string(buf, _num2);
else if (_num2==-1)
if (errno!=EINTR&&errno!=EAGAIN)
throw ExecutionFailedExc("readin stderr", *_cmd);
else
_num2 = 1;
if (_finish && !_input.size()) {
_stdIn->close_out();
_num0 = 0;
}
_finished = _finish && !_input.size() && !_num1 && !_num2 && _lastPid;
} catch (mrw::exception& x) {
_finished = true;
_success = false;
if (exc) throw;
return output;
}
if (_finished) _success = true;
return output;
}
//------------------------------------------------------------------------------
mrw::PartialExec& mrw::PartialExec::terminate() throw() {
::kill(_pid, SIGTERM);
return *this;
}
//------------------------------------------------------------------------------
mrw::PartialExec& mrw::PartialExec::kill() throw() {
::kill(_pid, SIGKILL);
return *this;
}

View File

@@ -1,134 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.9 2005/04/19 18:48:00 marc
new feature PartialExec
Revision 1.8 2005/04/07 20:55:21 marc
Oops, there's a make distcheck...? Now it works.
Revision 1.7 2004/12/20 13:21:21 marc
exception tests: each exception must be in an own test case
Revision 1.6 2004/12/14 20:30:10 marc
added possibility to pass string to stdin of child process
Revision 1.5 2004/10/13 10:43:11 marc
test for bad exception specification
Revision 1.4 2004/08/28 16:21:25 marc
mrw-c++-0.92 (mrw)
- new file: version.cxx
- new file header for all sources
- work around warning in mrw::auto<T>
- possibility to compile without log4cxx
- work around bugs in demangle.h and libiberty.h
- corrections in documentation
- added simple tracing mechanism
- more warnings
- small corrections in Auto<>::Free and a new test for it
- possibility to compile without stack trace
*/
#include <mrw/exec.hxx>
#include <mrw/stacktrace.hxx>
#include <mrw/stdext.hxx>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <string>
#include <stdlib.h>
#include <iostream>
#ifdef __GNUG__
#define LOG std::clog<<__PRETTY_FUNCTION__<<'@'<<__FILE__<<':'<<__LINE__;
#else
#define LOG std::clog<<__FUNCTION__<<'@'<<__FILE__<<':'<<__LINE__;
#endif
class ExecTest: public CppUnit::TestFixture {
public:
void lsTest() {
LOG;
std::string res = (mrw::Cmd("/bin/ls"), "-l",
std::string(getenv("srcdir"))+"/..").execute();
CPPUNIT_ASSERT(res.find("COPYING")<res.size());
}
void catTest() {
LOG;
std::string res = mrw::Cmd("/bin/cat").execute("This is a test");
CPPUNIT_ASSERT(res=="This is a test");
}
void excTest1() {
LOG;
std::string res = (mrw::Cmd("/bin/false")).execute().result();
}
void excTest2() {
LOG;
std::string res = (mrw::Cmd("/bin/false")).execute("").result();
}
void unexpectedExc() throw(std::bad_exception) {
LOG;
std::string res = (mrw::Cmd("/bin/false")).execute().result();
}
void lsTest2() {
LOG;
std::string res;
mrw::PartialExec exec = (mrw::Cmd("/bin/ls"), "-l",
std::string(getenv("srcdir"))+"/..").start();
while (!exec.finished()) res+=exec.read().first;
CPPUNIT_ASSERT(res.find("COPYING")<res.size());
}
void catTest2() {
LOG;
mrw::PartialExec exec = mrw::Cmd("/bin/cat").start(true);
std::string res = exec.read("This is a test\n").first;
res += exec.read("More to come...\n").first;
exec.finish();
while (!exec.finished()) res+=exec.read().first;
CPPUNIT_ASSERT(res=="This is a test\nMore to come...\n");
}
void excTest12() {
LOG;
mrw::PartialExec exec = (mrw::Cmd("/bin/false")).start();
while (!exec.finished()) exec.read();
}
void excTest22() {
LOG;
mrw::PartialExec exec = (mrw::Cmd("/bin/false")).start(true);
while (!exec.finished()) exec.read("xxx");
}
void unexpectedExc2() throw(std::bad_exception) {
LOG;
mrw::PartialExec exec = (mrw::Cmd("/bin/false")).start();
while (!exec.finished()) exec.read();
}
CPPUNIT_TEST_SUITE(ExecTest);
CPPUNIT_TEST(lsTest);
CPPUNIT_TEST(catTest);
CPPUNIT_TEST_EXCEPTION(excTest1, mrw::ExecutionFailedExc);
CPPUNIT_TEST_EXCEPTION(excTest2, mrw::ExecutionFailedExc);
CPPUNIT_TEST_EXCEPTION(unexpectedExc, std::bad_exception);
CPPUNIT_TEST(lsTest2);
CPPUNIT_TEST(catTest2);
CPPUNIT_TEST_EXCEPTION(excTest12, mrw::ExecutionFailedExc);
CPPUNIT_TEST_EXCEPTION(excTest22, mrw::ExecutionFailedExc);
CPPUNIT_TEST_EXCEPTION(unexpectedExc2, std::bad_exception);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(ExecTest);
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,22 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.1 2005/03/11 21:07:54 marc
initial version
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#include <mrw/functiontrace.hxx>
unsigned int mrw::FnTrace::_level(0);

View File

@@ -1,133 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.3 2005/04/07 20:55:21 marc
Oops, there's a make distcheck...? Now it works.
Revision 1.2 2005/03/11 23:18:02 marc
bugfix: linenumbers change at checkin...
Revision 1.1 2005/03/11 21:07:55 marc
initial version
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#include <mrw/functiontrace.hxx>
#include <mrw/regexp.hxx>
#include <mrw/file.hxx>
#include <log4cxx/propertyconfigurator.h>
#include <log4cxx/helpers/properties.h>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
class A {
public:
A() {
MRW_METHOD("A::A()");
}
~A() {
MRW_METHOD("A::~A()");
}
void fn1() {
MRW_METHOD("A::fn1()");
fn2();
}
void fn2() {
MRW_METHOD("A::fn2()");
fn3();
fn4();
}
void fn3() {
MRW_METHOD("A::fn3()");
fn4();
}
void fn4(bool flag=true) {
MRW_METHOD("A::fn4()");
if (flag) fn4(false);
}
};
void fn(A a) {
MRW_FUNCTION("fn(A)");
a.fn1();
}
class FunctionTraceTest: public CppUnit::TestFixture {
public:
void Init() {
try {mrw::File::remove("functiontrace_test.log");} catch (...) {}
log4cxx::helpers::Properties properties;
std::string name, cont;
properties.setProperty((name="log4j.rootLogger",
log4cxx::String(name.begin(), name.end())),
(cont="DEBUG, A1",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.appender.A1",
log4cxx::String(name.begin(), name.end())),
(cont="org.apache.log4j.FileAppender",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.appender.A1.layout",
log4cxx::String(name.begin(), name.end())),
(cont="org.apache.log4j.PatternLayout",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.appender.A1.layout.ConversionPattern",
log4cxx::String(name.begin(), name.end())),
(cont="%F:%L - %m%n",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.appender.A1.filename",
log4cxx::String(name.begin(), name.end())),
(cont="functiontrace_test.log",
log4cxx::String(cont.begin(), cont.end())));
log4cxx::PropertyConfigurator::configure(properties);
}
void Calls() {
fn(A());
mrw::RegExp match
(".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: \\\\ A::A\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: / A::A\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - \\\\ fn\\(A\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: \\\\ A::fn1\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: \\\\ A::fn2\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: \\\\ A::fn3\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: \\\\ A::fn4\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: \\\\ A::fn4\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: / A::fn4\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: / A::fn4\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: / A::fn3\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: \\\\ A::fn4\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: \\\\ A::fn4\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: / A::fn4\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: / A::fn4\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: / A::fn2\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: / A::fn1\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - / fn\\(A\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: \\\\ A::~A\\(\\)\n"
".*functiontrace_test.cxx:[0-9]+ - *0x[0-9a-fA-F]+: / A::~A\\(\\)\n");
CPPUNIT_ASSERT(match(mrw::File::read("functiontrace_test.log")));
mrw::File::remove("functiontrace_test.log");
}
CPPUNIT_TEST_SUITE(FunctionTraceTest);
CPPUNIT_TEST(Init);
CPPUNIT_TEST(Calls);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(FunctionTraceTest);
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,223 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.3 2005/11/29 12:39:42 marc
make it compilable with gcc 4.0.2 and newer doxygen
Revision 1.2 2005/04/14 19:06:37 marc
no more duplicated traces, better filtering for Qt
Revision 1.1 2005/04/07 20:57:36 marc
initial version
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#include <log4cxx/propertyconfigurator.h>
#include <log4cxx/helpers/properties.h>
#include <fstream>
#if (__GNUC__==3 && __GNUC_MINOR__<4 || __GNUC__<3) \
&& defined(_REENTRANT) && !defined(_MT)
#define _MT
#endif
namespace mrw {
/** @addtogroup debug
*/
//@{
/** @defgroup AutoInitLog4cxx Automatically initialize log4cxx
If you want to enable log4cxx
(http://logging.apache.org/log4cxx), you have to configure it in
your application, normally in the main. If you want to configure
it automatically, without changing a single line in your code
(e.g. for temporary debugging), simply link to @c
libmrwlog4cxxconfiguration, either with option @c
-lmrwlog4cxxconfiguration for single threaded, or with @c
-lmrwlog4cxxconfiguration-mt for multi threaded applications.
With @ref trclog4cxx and @ref
AutoFunctionTrace, you can add tracing based on @c log4cxx,
without even change a single line in your code. But your code
still has to initialize @c log4cxx. If you even want to
automatically initialize @c log4cxx, use this library!
Configures @c log4cxx in the following way:
-# if available, read @c log4cxx property file
(read first file found, in this order)
-# file specified in environment variable
@c $MRW_LOG4CXX_CONFIGFILE
-# <code>.mrwlog4cxx</code> (local file)
-# <code>~/.mrwlog4cxx</code> (file in user's home)
-# <code>/etc/mrwlog4cxx</code> (global configuration)
-# if no configuration file is found, use default configuration:
@verbatim
log4j.rootLogger = WARN, A1
log4j.logger.mrw.fntrace = OFF
log4j.logger.mrw.fn = OFF
log4j.logger.mrw.fn.log4cxx = OFF
log4j.logger.mrw.fn.boost = OFF
log4j.logger.mrw.fn.Thread = OFF
log4j.logger.mrw.fn.QString = OFF
log4j.logger.mrw.fn.QShared = OFF
log4j.logger.mrw.fn.QWidget = OFF
log4j.logger.mrw.fn.QRect = OFF
log4j.logger.mrw.fn.qstrcmp = OFF
log4j.logger.mrw.fn.*.qt_cast = OFF
log4j.logger.mrw.fn.mrw = OFF
log4j.logger.mrw.fn.std = OFF
log4j.logger.mrw.fn.CppUnit = OFF
log4j.logger.mrw.fn.__gnu_cxx = OFF
log4j.appender.A1 = org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout = org.apache.log4j.PatternLayout
@endverbatim
and for multi threaded programs in addition:
@verbatim
log4j.appender.A1.layout.ConversionPattern = \%t-\%-40l - \%m\%n
@endverbatim
on the other hand, single threaded programs are formatted as:
@verbatim
log4j.appender.A1.layout.ConversionPattern = \%-40l - \%m\%n
@endverbatim
This results in the following behaviour:
- trace to console
- format as...
- @c "\%t-\%-40l - \%m\%n" if threaded
- @c "\%-40l - \%m\%n" if not threaded
- enable all tracing to @c DEBUG
- enable tracing of @ref AutoFunctionTrace
- disable function trace for @c log4cxx
- disable function trace for @c boost
- disable function trace for @c Qt base classes
- disable function trace for @c libmrw
- disable function trace for @c std
- disable function trace for @c CppUnit
- disable function trace for @c gcc internals
*/
//@{
class InitLog4cxx {
public:
InitLog4cxx() {
std::string logconfigfile;
char* c(getenv("MRW_LOG4CXX_CONFIGFILE"));
if (c && std::ifstream(c))
logconfigfile = c;
else if (std::ifstream(".mrwlog4cxx"))
logconfigfile = ".mrwlog4cxx";
else if ((c=getenv("HOME")) &&
std::ifstream((std::string(c)+"/.mrwlog4cxx").c_str()))
logconfigfile = std::string(c)+"/.mrwlog4cxx";
else if (std::ifstream("/etc/mrwlog4cxx"))
logconfigfile = "/etc/mrwlog4cxx";
if (logconfigfile.size()) {
log4cxx::PropertyConfigurator::configure
(log4cxx::String(logconfigfile.begin(), logconfigfile.end()));
return;
}
log4cxx::helpers::Properties properties;
std::string name, cont;
properties.setProperty((name="log4j.rootLogger",
log4cxx::String(name.begin(), name.end())),
(cont="WARN, A1",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fntracea",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.log4cxx",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.boost",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.Thread",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.QString",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.QShared",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.QWidget",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.QRect",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.qstrcmp",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.*.qt_cast",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.mrw",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.std",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.CppUnit",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.__gnu_cxx",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.appender.A1",
log4cxx::String(name.begin(), name.end())),
(cont="org.apache.log4j.ConsoleAppender",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.appender.A1.layout",
log4cxx::String(name.begin(), name.end())),
(cont="org.apache.log4j.PatternLayout",
log4cxx::String(cont.begin(), cont.end())));
#ifdef _MT
properties.setProperty((name="log4j.appender.A1.layout.ConversionPattern",
log4cxx::String(name.begin(), name.end())),
(cont="%t-%-40l - %m%n",
log4cxx::String(cont.begin(), cont.end())));
#else
properties.setProperty((name="log4j.appender.A1.layout.ConversionPattern",
log4cxx::String(name.begin(), name.end())),
(cont="%-40l - %m%n",
log4cxx::String(cont.begin(), cont.end())));
#endif
log4cxx::PropertyConfigurator::configure(properties);
}
};
static InitLog4cxx INIT_LOG4CXX;
//@}
//@}
}

View File

@@ -1,244 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.3 2005/11/29 12:39:42 marc
make it compilable with gcc 4.0.2 and newer doxygen
Revision 1.2 2005/04/07 20:42:38 marc
renamed loggerhierarchy from mrw.gccfunctiontrace to mrw.fn
Revision 1.1 2005/03/11 21:07:55 marc
initial version
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#include <log4cxx/propertyconfigurator.h>
#include <log4cxx/helpers/properties.h>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <mrw/file.hxx>
#include <mrw/regexp.hxx>
#include <mrw/string.hxx>
#include <mrw/stacktrace.hxx>
#include <map>
#if (__GNUC__==3 && __GNUC_MINOR__<4 || __GNUC__<3) \
&& defined(_REENTRANT) && !defined(_MT)
#define _MT
#endif
namespace HalloWelt {
class A {
public:
void method() {
}
};
void fn(int) {
A().method();
A().method();
}
void fn1() {
fn(1);
fn(2);
}
}
void anotherFunction() {
HalloWelt::fn1();
}
#ifdef _MT
#include <boost/thread/thread.hxx>
//#include <unistd.h> // sleep, the one from boost::thread does not work!
class Thread {
public:
void operator()() {
anotherFunction();
}
};
#endif
namespace mrw {
class AutoFunctionTraceLog4CxxTest: public CppUnit::TestFixture {
public:
void testcase() {
mrw::StackTrace::createSymtable();
#ifdef _MT
try {mrw::File::remove("mrwautofunctiontracelog4cxx_test-mt.log");}
#else
try {mrw::File::remove("mrwautofunctiontracelog4cxx_test.log");}
#endif
catch (...) {}
log4cxx::helpers::Properties properties;
std::string name, cont;
properties.setProperty((name="log4j.rootLogger",
log4cxx::String(name.begin(), name.end())),
(cont="OFF, A1",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn",
log4cxx::String(name.begin(), name.end())),
(cont="DEBUG",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.global",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.allocator",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.std.*",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.log4cxx",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.boost",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.Thread",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.mrw",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.std",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.new",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.CppUnit",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.logger.mrw.fn.__gnu_cxx",
log4cxx::String(name.begin(), name.end())),
(cont="OFF",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.appender.A1",
log4cxx::String(name.begin(), name.end())),
(cont="org.apache.log4j.FileAppender",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.appender.A1.layout",
log4cxx::String(name.begin(), name.end())),
(cont="org.apache.log4j.PatternLayout",
log4cxx::String(cont.begin(), cont.end())));
#ifdef _MT
properties.setProperty((name="log4j.appender.A1.layout.ConversionPattern",
log4cxx::String(name.begin(), name.end())),
(cont="%t-%-27c%m%n",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.appender.A1.filename",
log4cxx::String(name.begin(), name.end())),
(cont="mrwautofunctiontracelog4cxx_test-mt.log",
log4cxx::String(cont.begin(), cont.end())));
#else
properties.setProperty((name="log4j.appender.A1.layout.ConversionPattern",
log4cxx::String(name.begin(), name.end())),
(cont="%-27c%m%n",
log4cxx::String(cont.begin(), cont.end())));
properties.setProperty((name="log4j.appender.A1.filename",
log4cxx::String(name.begin(), name.end())),
(cont="mrwautofunctiontracelog4cxx_test.log",
log4cxx::String(cont.begin(), cont.end())));
#endif
log4cxx::PropertyConfigurator::configure(properties);
#ifdef _MT
// sleep(4); // to be reproducable, wait for "main" flag
Thread threadFunction;
boost::thread::thread thread1(threadFunction);
boost::thread::thread thread2(threadFunction);
boost::thread::thread thread3(threadFunction);
#endif
anotherFunction();
#ifdef _MT
thread1.join();
thread2.join();
thread3.join();
#endif
}
void checkfile() {
mrw::RegExp match
("^mrw\\.fn\\.anotherFunction ( ? ? ?)\\\\ anotherFunction\\(\\)\n"
"mrw\\.fn\\.HalloWelt\\.fn1 \\1 \\\\ HalloWelt::fn1\\(\\)\n"
"mrw\\.fn\\.HalloWelt\\.fn \\1 \\\\ HalloWelt::fn\\(int\\)\n"
"mrw\\.fn\\.HalloWelt\\.A\\.method \\1 \\\\ HalloWelt::A::method\\(\\)\n"
"mrw\\.fn\\.HalloWelt\\.A\\.method \\1 / HalloWelt::A::method\\(\\)\n"
"mrw\\.fn\\.HalloWelt\\.A\\.method \\1 \\\\ HalloWelt::A::method\\(\\)\n"
"mrw\\.fn\\.HalloWelt\\.A\\.method \\1 / HalloWelt::A::method\\(\\)\n"
"mrw\\.fn\\.HalloWelt\\.fn \\1 / HalloWelt::fn\\(int\\)\n"
"mrw\\.fn\\.HalloWelt\\.fn \\1 \\\\ HalloWelt::fn\\(int\\)\n"
"mrw\\.fn\\.HalloWelt\\.A\\.method \\1 \\\\ HalloWelt::A::method\\(\\)\n"
"mrw\\.fn\\.HalloWelt\\.A\\.method \\1 / HalloWelt::A::method\\(\\)\n"
"mrw\\.fn\\.HalloWelt\\.A\\.method \\1 \\\\ HalloWelt::A::method\\(\\)\n"
"mrw\\.fn\\.HalloWelt\\.A\\.method \\1 / HalloWelt::A::method\\(\\)\n"
"mrw\\.fn\\.HalloWelt\\.fn \\1 / HalloWelt::fn\\(int\\)\n"
"mrw\\.fn\\.HalloWelt\\.fn1 \\1 / HalloWelt::fn1\\(\\)\n"
"mrw\\.fn\\.anotherFunction \\1/ anotherFunction\\(\\)\n$");
#ifdef _MT
std::string log(mrw::File::read("mrwautofunctiontracelog4cxx_test-mt.log"));
typedef std::map<unsigned long, std::string> Logs;
Logs logs;
for (std::string::size_type pos(0), last(0);
(pos=log.find('\n', pos+1))!=std::string::npos; last=pos) {
std::string::size_type dash(log.find('-', last));
CPPUNIT_ASSERT_MESSAGE("\"-\" not found",
dash!=std::string::npos);
logs[mrw::to<unsigned long>(log.substr(last, dash-last))] +=
log.substr(dash+1, pos-dash);
}
CPPUNIT_ASSERT_EQUAL((Logs::size_type)4, logs.size()); // 4 threads
for (Logs::iterator it(logs.begin()); it!=logs.end(); ++it)
CPPUNIT_ASSERT_MESSAGE("The following text does not match the "
"Expectation:\n--------------------\n"
+it->second+"--------------------",
match(it->second));
mrw::File::remove("mrwautofunctiontracelog4cxx_test-mt.log");
#else
CPPUNIT_ASSERT_MESSAGE
("The following text does not match the "
"Expectation:\n--------------------\n"
+mrw::File::read("mrwautofunctiontracelog4cxx_test.log")
+"--------------------",
match(mrw::File::read("mrwautofunctiontracelog4cxx_test.log")));
mrw::File::remove("mrwautofunctiontracelog4cxx_test.log");
#endif
}
CPPUNIT_TEST_SUITE(AutoFunctionTraceLog4CxxTest);
CPPUNIT_TEST(testcase);
CPPUNIT_TEST(checkfile);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(AutoFunctionTraceLog4CxxTest);
}
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,93 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.2 2004/08/28 16:21:25 marc
mrw-c++-0.92 (mrw)
- new file: version.cxx
- new file header for all sources
- work around warning in mrw::auto<T>
- possibility to compile without log4cxx
- work around bugs in demangle.h and libiberty.h
- corrections in documentation
- added simple tracing mechanism
- more warnings
- small corrections in Auto<>::Free and a new test for it
- possibility to compile without stack trace
*/
#include <mrw/exception.hxx>
#include <log4cxx/basicconfigurator.h>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
namespace mrw {
class AutoExcLog4CxxTest: public CppUnit::TestFixture {
private:
bool enter_unexpectedThrow;
bool exit_unexpectedThrow;
bool enter_passUnexpected;
bool exit_passUnexpected;
bool enter_catchUnexpected;
bool exit_catchUnexpected;
public:
void setUp() {
enter_unexpectedThrow = false;
exit_unexpectedThrow = false;
enter_passUnexpected = false;
exit_passUnexpected = false;
enter_catchUnexpected = false;
exit_catchUnexpected = false;
}
void unexpectedThrow() throw(std::bad_exception) {
enter_unexpectedThrow = true;
throw mrw::exception();
exit_unexpectedThrow = true;
}
void passUnexpected() throw(std::bad_exception) {
enter_passUnexpected = true;
unexpectedThrow();
exit_passUnexpected = true;
}
void catchUnexpected() throw() {
enter_catchUnexpected = true;
bool caught(false);
try {
passUnexpected();
} catch (std::bad_exception&) {
caught = true;
}
CPPUNIT_ASSERT(caught);
exit_catchUnexpected = true;
}
void testcase() {
catchUnexpected();
CPPUNIT_ASSERT(enter_catchUnexpected &&
enter_passUnexpected &&
enter_unexpectedThrow &&
exit_catchUnexpected &&
!exit_passUnexpected &&
!exit_unexpectedThrow);
}
CPPUNIT_TEST_SUITE(AutoExcLog4CxxTest);
CPPUNIT_TEST(testcase);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(AutoExcLog4CxxTest);
}
int main() {
log4cxx::BasicConfigurator::configure();
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,91 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.2 2004/08/28 16:21:25 marc
mrw-c++-0.92 (mrw)
- new file: version.cxx
- new file header for all sources
- work around warning in mrw::auto<T>
- possibility to compile without log4cxx
- work around bugs in demangle.h and libiberty.h
- corrections in documentation
- added simple tracing mechanism
- more warnings
- small corrections in Auto<>::Free and a new test for it
- possibility to compile without stack trace
*/
#include <mrw/exception.hxx>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
namespace mrw {
class AutoExcStderrTest: public CppUnit::TestFixture {
private:
bool enter_unexpectedThrow;
bool exit_unexpectedThrow;
bool enter_passUnexpected;
bool exit_passUnexpected;
bool enter_catchUnexpected;
bool exit_catchUnexpected;
public:
void setUp() {
enter_unexpectedThrow = false;
exit_unexpectedThrow = false;
enter_passUnexpected = false;
exit_passUnexpected = false;
enter_catchUnexpected = false;
exit_catchUnexpected = false;
}
void unexpectedThrow() throw(std::bad_exception) {
enter_unexpectedThrow = true;
throw mrw::exception();
exit_unexpectedThrow = true;
}
void passUnexpected() throw(std::bad_exception) {
enter_passUnexpected = true;
unexpectedThrow();
exit_passUnexpected = true;
}
void catchUnexpected() throw() {
enter_catchUnexpected = true;
bool caught(false);
try {
passUnexpected();
} catch (std::bad_exception&) {
caught = true;
}
CPPUNIT_ASSERT(caught);
exit_catchUnexpected = true;
}
void testcase() {
catchUnexpected();
CPPUNIT_ASSERT(enter_catchUnexpected &&
enter_passUnexpected &&
enter_unexpectedThrow &&
exit_catchUnexpected &&
!exit_passUnexpected &&
!exit_unexpectedThrow);
}
CPPUNIT_TEST_SUITE(AutoExcStderrTest);
CPPUNIT_TEST(testcase);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(AutoExcStderrTest);
}
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,54 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.2 2004/12/16 13:09:31 marc
possibility to evaluate and extract sub expressions
Revision 1.1 2004/12/14 20:20:30 marc
initial version
*/
#include <mrw/string.hxx>
#include <mrw/regexp.hxx>
#include <mrw/exception.hxx>
namespace mrw {
RegExp::RegExp(const std::string& pattern, bool hassub, int flags)
throw(std::exception):
_hassub(hassub) {
if (flags&nosub) throw mrw::invalid_argument("nosub");
if (regcomp(&_regex, pattern.c_str(), (_hassub?flags:(flags|nosub))))
throw mrw::invalid_argument(pattern);
}
RegExp::~RegExp() throw() {
regfree(&_regex);
}
bool RegExp::operator()(const std::string& text) throw(std::bad_exception) {
if (_hassub)
return !regexec(&_regex, (_text=text).c_str(), MAX_SUB, _sub, 0);
else
return !regexec(&_regex, text.c_str(), 0, 0, 0);
}
std::string RegExp::operator[](unsigned int n) const throw(std::exception) {
if (!_hassub)
throw mrw::invalid_argument("initialized with no sub expressions");
if (n>=MAX_SUB || _sub[n].rm_so<0 || _sub[n].rm_eo<0)
throw mrw::invalid_argument(mrw::string(n));
return _text.substr(_sub[n].rm_so, _sub[n].rm_eo-_sub[n].rm_so);
}
}

View File

@@ -1,63 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.2 2004/12/16 13:09:31 marc
possibility to evaluate and extract sub expressions
Revision 1.1 2004/12/14 20:20:30 marc
initial version
*/
#include <mrw/regexp.hxx>
#include <mrw/exception.hxx>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
class RegExpTest: public CppUnit::TestFixture {
public:
void CheckRegExp() {
mrw::RegExp findHalloWelt("^Hallo.*Welt$");
CPPUNIT_ASSERT(findHalloWelt("Hallo Meine Welt"));
CPPUNIT_ASSERT(!findHalloWelt("xxx"));
CPPUNIT_ASSERT(!findHalloWelt(""));
CPPUNIT_ASSERT(!findHalloWelt(" Hallo Welt "));
CPPUNIT_ASSERT(findHalloWelt("HalloWelt"));
mrw::RegExp extractTest("^Guten (.*) (Herr|Frau) (.*)$", true);
CPPUNIT_ASSERT(extractTest("Guten Tag Frau Zuercher"));
CPPUNIT_ASSERT(extractTest[1]=="Tag" &&
extractTest[2]=="Frau" &&
extractTest[3]=="Zuercher");
}
void ExceptionTest() {
mrw::RegExp extractTest("^Guten (.*) (Herr|Frau) (.*)$", true);
CPPUNIT_ASSERT(extractTest("Guten Tag Herr Schweizer"));
CPPUNIT_ASSERT(extractTest[1]=="Tag" &&
extractTest[2]=="Herr" &&
extractTest[3]=="Schweizer");
std::string s = extractTest[4];
}
CPPUNIT_TEST_SUITE(RegExpTest);
CPPUNIT_TEST(CheckRegExp);
CPPUNIT_TEST_EXCEPTION(ExceptionTest, mrw::invalid_argument);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(RegExpTest);
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,162 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.1 2004/08/28 16:13:42 marc
mrw-c++-0.92 (mrw)
- new file: version.cxx
- new file header for all sources
- work around warning in mrw::auto<T>
- possibility to compile without log4cxx
- work around bugs in demangle.h and libiberty.h
- corrections in documentation
- added simple tracing mechanism
- more warnings
- small corrections in Auto<>::Free and a new test for it
- possibility to compile without stack trace
*/
#include <mrw/smartpointer.hxx>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <string>
class Content {
private:
int& _drop;
Content();
public:
Content(int& drop): _drop(drop) {}
virtual ~Content() {++_drop;}
};
class A: public Content {public: A(int& d): Content(d) {} virtual void fn() {}};
class B: public A {public: B(int& d): A(d) {}};
class C: public A {public: C(int& d): A(d) {}};
class SmartPointerTest:
public mrw::SmartPointerParent, public CppUnit::TestFixture {
public:
void SimpleConstructor() {
mrw::SmartPointer<Content> p1;
CPPUNIT_ASSERT(!(getPointer(p1) || getCounter(p1)));
}
void CopyConstructor() {
mrw::SmartPointer<Content> p1;
mrw::SmartPointer<Content> p2(p1);
CPPUNIT_ASSERT(!(getPointer(p1) || getCounter(p1) ||
getPointer(p2) || getCounter(p2)));
}
void PointerConstructor() {
int drops(0);
mrw::SmartPointer<Content> p1(0);
mrw::SmartPointer<Content> p2(new Content(drops));
CPPUNIT_ASSERT(!(getPointer(p1) || getCounter(p1) ||
drops!=0 || !getPointer(p2) || !getCounter(p2) ||
getCounter(p2)->get()!=1));
}
void CastConstructor() {
int drops1(0);
mrw::SmartPointer<A> pa(new B(drops1));
mrw::SmartPointer<B> pb(pa);
mrw::SmartPointer<C> pc(pa);
mrw::SmartPointer<A> pa2(pb);
CPPUNIT_ASSERT(!(drops1!=0 || !getPointer(pa) || !getCounter(pa) ||
getPointer(pb)!=getPointer(pa) ||
getCounter(pb)!=getCounter(pa) ||
getPointer(pc) || getCounter(pc) ||
getCounter(pa)->get()!=3 ||
getPointer(pa2)!=getPointer(pa) ||
getCounter(pa2)!=getCounter(pa)));
}
void Destructor() {
int drops(0);
mrw::SmartPointer<Content>* p1 =
new mrw::SmartPointer<Content>(new Content(drops));
delete p1;
CPPUNIT_ASSERT(!(drops!=1));
}
void CopyAssign() {
int drops1(0);
int drops2(0);
mrw::SmartPointer<Content> p1(new Content(drops1));
mrw::SmartPointer<Content> p2(new Content(drops2));
p2 = p1;
p1 = p2;
CPPUNIT_ASSERT(!(drops1!=0 || !getPointer(p1) || !getCounter(p1) ||
getCounter(p1)->get()!=2 ||
getPointer(p1)!=getPointer(p2) ||
drops2!=1 || !getPointer(p2) || !getCounter(p2) ||
getCounter(p2)->get()!=2 ||
getCounter(p1)!=getCounter(p2)));
}
void PointerAssign() {
int drops1(0);
int drops2(0);
int drops3(0);
mrw::SmartPointer<Content> p1(new Content(drops1));
mrw::SmartPointer<Content> p2(0);
p1 = new Content(drops2);
p1 = 0;
p2 = new Content(drops3);
CPPUNIT_ASSERT(!(drops1!=1 || getPointer(p1) || getCounter(p1) ||
drops2!=1 || !getPointer(p2) || !getCounter(p2) ||
drops3!=0 || getCounter(p2)->get()!=1));
}
void CastAssign() {
int drops1(0);
int drops2(0);
int drops3(0);
mrw::SmartPointer<A> pa(new B(drops1));
mrw::SmartPointer<B> pb(new B(drops2));
mrw::SmartPointer<C> pc(new C(drops3));
pa = pa;
pa = pb;
pa = pc;
pb = pa;
pc = pa;
CPPUNIT_ASSERT(!(drops1!=1 || drops2!=1 || drops3!=0 ||
!getPointer(pa) || getPointer(pa)!=getPointer(pc) ||
!getCounter(pa) || getCounter(pa)!=getCounter(pc) ||
getCounter(pa)->get()!=2 || getPointer(pb) ||
getCounter(pb)));
}
void PointerAccess() {
mrw::SmartPointer<std::string> p1(new std::string);
mrw::SmartPointer<std::string> p2;
*p1 = "Hallo Welt!";
CPPUNIT_ASSERT(!(p1.operator->()!=&*p1 || p1->find("Welt")!=6 ||
p2.operator->()));
}
void OperatorBool() {
mrw::SmartPointer<std::string> p1(new std::string);
mrw::SmartPointer<std::string> p2;
CPPUNIT_ASSERT(!(!p1 || p2));
}
CPPUNIT_TEST_SUITE(SmartPointerTest);
CPPUNIT_TEST(SimpleConstructor);
CPPUNIT_TEST(CopyConstructor);
CPPUNIT_TEST(PointerConstructor);
CPPUNIT_TEST(CastConstructor);
CPPUNIT_TEST(Destructor);
CPPUNIT_TEST(CopyAssign);
CPPUNIT_TEST(PointerAssign);
CPPUNIT_TEST(CastAssign);
CPPUNIT_TEST(PointerAccess);
CPPUNIT_TEST(OperatorBool);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(SmartPointerTest);
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,387 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
*/
#include <mrw/stacktrace.hxx>
#include <mrw/exec.hxx>
#include <mrw/string.hxx>
#include <mrw/list.hxx>
#include <mrw/stdext.hxx>
#ifndef NO_LTDL
# include <mrw/dynamiclibrary.hxx>
#endif
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <assert.h>
#include <math.h>
#include <fstream>
#include <algorithm>
#include <list>
#if defined(__solaris__)
#include <sys/old_procfs.h>
#endif
#if defined (__GLIBC__)
#include <execinfo.h>
#endif
#include <bfd.h>
#include <iomanip>
#if HAVE_DEMANGLE_H
/* the defines work around wrong definitions in libiberty.h */
#define HAVE_DECL_BASENAME 1
#define HAVE_DECL_FFS 1
#define HAVE_DECL_ASPRINTF 1
#define HAVE_DECL_VASPRINTF 1
#define HAVE_DECL_SNPRINTF 1
#define HAVE_DECL_VSNPRINTF 1
#define HAVE_DECL_STRVERSCMP 1
# include <demangle.h>
#else
# define DMGL_PARAMS (1 << 0) /* Include function args */
# define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
extern "C" {
extern char * cplus_demangle(const char *, int);
}
#endif
#if (__GNUC__==3 && __GNUC_MINOR__<4 || __GNUC__<3) \
&& defined(_REENTRANT) && !defined(_MT)
#define _MT
#endif
namespace mrw {
//----------------------------------------------------------------------------
static std::string demangle(bfd* abfd, const char* name) {
if (bfd_get_symbol_leading_char(abfd) == name[0]) ++name;
/* This is a hack for better error reporting on XCOFF, PowerPC64-ELF
or the MS PE format. These formats have a number of leading '.'s
on at least some symbols, so we remove all dots to avoid
confusing the demangler. */
const char* p(name);
while (p && *p == '.') ++p;
# ifdef __solaris__
char res[1024];
if (cplus_demangle(p, res, 1024)) return name;
# else
Auto<char*>::Free res(cplus_demangle(p, DMGL_ANSI | DMGL_PARAMS));
# endif
if (res) {
/* Now put back any stripped dots. */
if (p==name) return static_cast<const char*>(res);
std::string add_dots('.', p-name);
return add_dots+=static_cast<const char*>(res);
}
return name;
}
}
//----------------------------------------------------------------------------
mrw::StackTrace::StackTrace() throw(std::bad_exception) {
// maximum trace level is limited here to 50, see below why
# if defined(__GNUG__)
{
# define PUSH(i) \
(__builtin_frame_address(i)!=0 ? \
(_trace.push_back(__builtin_return_address(i)), true) : false)
PUSH(0) && PUSH(1) && PUSH(2) && PUSH(3) && PUSH(4) && PUSH(5) &&
PUSH(6) && PUSH(7) && PUSH(8) && PUSH(9) && PUSH(10) && PUSH(11) &&
PUSH(12) && PUSH(13) && PUSH(14) && PUSH(15) && PUSH(16) && PUSH(17)
&& PUSH(18) && PUSH(19) && PUSH(20) && PUSH(21) && PUSH(22) &&
PUSH(23) && PUSH(24) && PUSH(25) && PUSH(26) && PUSH(27) && PUSH(28)
&& PUSH(29) && PUSH(30) && PUSH(31) && PUSH(32) && PUSH(33) &&
PUSH(34) && PUSH(35) && PUSH(36) && PUSH(37) && PUSH(38) && PUSH(39)
&& PUSH(40) && PUSH(41) && PUSH(42) && PUSH(43) && PUSH(44) &&
PUSH(45) && PUSH(46) && PUSH(47) && PUSH(48) && PUSH(49);
# undef PUSH
}
# elif defined(__GLIBC__)
{
const int TRACE_LEVEL(50);
void* ba[TRACE_LEVEL];
for (int n(backtrace(ba, TRACE_LEVEL)), i(0); i<n; ++i)
_trace.push_back(ba[i]);
}
# else
# warning "You need GNU gcc or GNU glibc to be able to use mrw::StackTrace"
# endif
}
mrw::StackTrace::~StackTrace() throw() {
// maximum trace level is limited here to 50, see below why
# if !defined(__GNUG__) && defined(__GLIBC__)
/* GLIBC backtrace seems to leak memory, but I don't see why, so
GNUG part is prefered. According to the man-page, backtrace does
not allocate memory, so what happens here? Valgrind message:
==19829== 28 bytes in 1 blocks are still reachable in loss record 1 of 1
==19829== at 0x40233F0: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==19829== by 0x400CE43: _dl_map_object_deps (in /lib/ld-2.5.so)
==19829== by 0x4011E34: dl_open_worker (in /lib/ld-2.5.so)
==19829== by 0x400E025: _dl_catch_error (in /lib/ld-2.5.so)
==19829== by 0x4011928: _dl_open (in /lib/ld-2.5.so)
==19829== by 0x44AFF01: do_dlopen (in /lib/libc-2.5.so)
==19829== by 0x400E025: _dl_catch_error (in /lib/ld-2.5.so)
==19829== by 0x44B0000: dlerror_run (in /lib/libc-2.5.so)
==19829== by 0x44B012A: __libc_dlopen_mode (in /lib/libc-2.5.so)
==19829== by 0x448E2A8: init (in /lib/libc-2.5.so)
==19829== by 0x448E452: backtrace (in /lib/libc-2.5.so)
==19829== by 0x40E7E53: mrw::StackTrace::StackTrace() (in libmrw.so.3.2.0)
{
<insert a suppression name here>
Memcheck:Leak
fun:_vgrZU_libcZdsoZa_malloc
fun:_dl_map_object_deps
fun:dl_open_worker
fun:_dl_catch_error
fun:_dl_open
fun:do_dlopen
fun:_dl_catch_error
fun:dlerror_run
fun:__libc_dlopen_mode
fun:init
fun:backtrace
fun:_ZN3mrw10StackTraceC1Ev
}
*/
# endif
}
//----------------------------------------------------------------------------
mrw::StackTrace::operator std::string() const throw(std::bad_exception) {
std::stringstream s;
bool first(true);
unsigned int fusz(0), adsz(0); //lisz(0), fisz(0)
std::list<CodePos> l;
for (AddressTrace::const_reverse_iterator it(_trace.rbegin());
it!=_trace.rend(); ++it, first=false) {
CodePos c(translate(*it));
if (((std::stringstream&)(std::stringstream()<<c.address)).str().size()
> adsz)
adsz =
((std::stringstream&)(std::stringstream()<<c.address)).str().size();
if (c.function.size() > fusz) fusz = c.function.size();
l.push_back(c);
}
for (std::list<CodePos>::iterator it(l.begin()); it!=l.end(); ++it)
s<<'['<<std::setw(adsz)<<it->address<<"] "
<<it->function<<std::setw(fusz-it->function.size()+1)<<' '
<<it->file<<':'<<it->line<<std::endl;
return s.str();
}
//----------------------------------------------------------------------------
const mrw::StackTrace& mrw::StackTrace::print(std::ostream& os) const
throw(std::bad_exception) {
os<<(std::string)*this;
return *this;
}
//----------------------------------------------------------------------------
mrw::StackTrace::CodePos mrw::StackTrace::translate(void* addr)
throw(std::bad_exception) {
#ifdef _MT
boost::recursive_mutex::scoped_lock lock(_mutex);
#endif
static const CodePos UNKNOWN(addr, "????", "????", 0);
assert(sizeof(bfd_vma)>=sizeof(void*));
bfd_vma vma_addr(reinterpret_cast<bfd_vma>(addr));
std::map<Translator::key_type, std::string>::iterator
it(_addrs.lower_bound(vma_addr));
if (it==_addrs.begin() || (--it)->first > vma_addr ||
_dic.find(it->second)==_dic.end() ||
_dic[it->second][it->first].first <= vma_addr)
return UNKNOWN;
static const char* file(0);
static const char* function(0);
unsigned int line;
if (!bfd_find_nearest_line
(const_cast<bfd*>(static_cast<const bfd*>(_bfd[it->second])),
_dic[it->second][it->first].second,
_syms[it->second],
vma_addr - it->first,
&file, &function, &line))
return UNKNOWN;
return CodePos(addr, mrw::demangle(_bfd[it->second], function),
file?file:"????", line);
}
//----------------------------------------------------------------------------
bool mrw::StackTrace::createSymtable(const std::string& fname, void* offs)
throw(std::bad_exception) {
#ifdef _MT
boost::recursive_mutex::scoped_lock lock(_mutex);
#endif
if (_dic.find(fname)!=_dic.end()) return true; // already loaded
try {
#if NO_LTDL
static bfd*(*bfd_openr)(const char*, const char*) =
::bfd_openr;
static bfd_boolean(*bfd_check_format)(bfd*, bfd_format) =
::bfd_check_format;
static bfd_boolean(*bfd_check_format_matches)(bfd*, bfd_format, char***) =
::bfd_check_format_matches;
static void(*bfd_map_over_sections)
(bfd*, void(*)(bfd*, asection*, void*), void*) =
::bfd_map_over_sections;
#else
static DynamicLibrary lib("libbfd");
static bfd*(*bfd_openr)(const char*, const char*) =
(bfd*(*)(const char*, const char*))lib.symbol("bfd_openr");
static bfd_boolean(*bfd_check_format)(bfd*, bfd_format) =
(bfd_boolean(*)(bfd*, bfd_format))lib.symbol("bfd_check_format");
static bfd_boolean(*bfd_check_format_matches)(bfd*, bfd_format, char***) =
(bfd_boolean(*)(bfd*, bfd_format, char***))
lib.symbol("bfd_check_format_matches");
static void(*bfd_map_over_sections)
(bfd*, void(*)(bfd*, asection*, void*), void*) =
(void(*)(bfd*, void(*)(bfd*, asection*, void*), void*))
lib.symbol("bfd_map_over_sections");
#endif
if (fname=="") return createSymtable(filename());
AutoBfd abfd((*bfd_openr)(fname.c_str(), 0));
long memsz(-1);
Auto<char**>::Free m(0);
if (!abfd || (*bfd_check_format)(abfd, bfd_archive) ||
!(*bfd_check_format_matches)(abfd, bfd_object, &(m.getClean())) ||
!(bfd_get_file_flags(const_cast<bfd*>(static_cast<const bfd*>(abfd)))
&HAS_SYMS) ||
(memsz=bfd_get_symtab_upper_bound
(const_cast<bfd*>(static_cast<const bfd*>(abfd))))<0) {
_error = "cannot map bfd symbols - 'bfd_get_file_flags' failed "
"for file: \""+fname+'"';
return false;
}
mrw::AutoPtrAry<asymbol*> syms(new asymbol*[memsz]);
if (bfd_canonicalize_symtab(const_cast<bfd*>(static_cast<const bfd*>(abfd)),
syms)<0) {
_error = "cannot map bfd symbols - 'bfd_canonicalize_symtab' failed"
"for file: \""+fname+'"';
return false;
}
_bfd[fname] = abfd;
_syms[fname] = syms;
_dic[fname];
std::pair<std::string, void*> fileoffs = std::make_pair(fname, offs);
(*bfd_map_over_sections)(_bfd[fname], buildSectionMap, &fileoffs);
return true;
} catch (const std::exception& x) {
_error = std::string("exception received: \"")+x.what()+"\", "
"while processing file: \""+fname+'"';
return false; // shared library for bfd not found or similar
}
}
//----------------------------------------------------------------------------
bool mrw::StackTrace::createSymtable(const mrw::StackTrace::BinFiles& files)
throw(std::bad_exception) {
#ifdef _MT
boost::recursive_mutex::scoped_lock lock(_mutex);
#endif
bool success(true);
for (BinFiles::const_iterator it(files.begin());
it!=files.end(); ++it) {
if (!createSymtable(it->first, it->second)) success=false;
}
return success;
}
//----------------------------------------------------------------------------
int mrw::StackTrace::bfdClose(bfd* abfd) throw() {
try {
#if NO_LTDL
static int(*bfd_close)(bfd*) = ::bfd_close;
#else
static DynamicLibrary lib("");
static int(*bfd_close)(bfd*) = (int(*)(bfd*))lib.symbol("bfd_close");
#endif
return (*bfd_close)(abfd);
} catch (...) {
return -1; // dynamic library loading problems
}
}
//----------------------------------------------------------------------------
mrw::StackTrace::BinFiles mrw::StackTrace::filename()
throw(std::bad_exception) {
mrw::StackTrace::BinFiles res;
# if defined(__solaris__)
{
std::string s;
s<<"/proc/"<<getpid();
AutoFile fd(open(s.c_str(), O_RDONLY));
prpsinfo_t status;
if (fd==-1 || ioctl(fd, PIOCPSINFO, &status)==-1) return res;
s = status.pr_psargs;
return res<<BinFiles::value_type(s.substr(0, s.find(' ')), 0);
}
# elif defined(__linux__)
{
res<<BinFiles::value_type("/proc/self/exe", 0);
std::ifstream is("/proc/self/maps");
std::string s;
std::string range, perm, x1, x2, size, lib;
while (getline(is, s)) try {
range = perm = x1 = x2 = size = lib = "????";
s>>range>>perm>>x1>>x2>>size>>lib;
range.resize(range.find_first_not_of("0123456789abcdefABCDEF"));
void* addr(0);
range>>addr;
// added check: no names in brackets: [lib], because there are
// [heap], [stack] and [vdso] that cannot be loaded
// question: should only files with ending '.so' be loaded?
if (lib.size() && lib[0]!='[' && lib[lib.size()-1]!=']' && addr>0)
res<<BinFiles::value_type(lib, addr);
} catch (...) {} // ignore non matching lines
return res;
}
# else
{
# warning "Don't know how to get executable file name in your system!"
# warning "Impossible to get function names in stack trace!"
# warning "Give the path to the executable to StackTrace::createSymtable!"
return res; // empty
}
# endif
}
//----------------------------------------------------------------------------
void mrw::StackTrace::buildSectionMap(bfd* abfd, asection* section,
void* fileoffs)
throw(std::bad_exception) {
if (!abfd || !section || !fileoffs) return;
if (!(bfd_get_section_flags(abfd, section)&SEC_ALLOC)) return;
std::pair<std::string, void*> fileoffset =
*(std::pair<std::string, void*>*)fileoffs;
bfd_vma vma(bfd_get_section_vma(abfd, section)+
reinterpret_cast<bfd_vma>(fileoffset.second));
#ifdef bfd_get_section_size
bfd_size_type sz(bfd_get_section_size(section));
#elif defined bfd_get_section_size_before_reloc
bfd_size_type sz(bfd_get_section_size_before_reloc(section));
#else
bfd_size_type sz(section->size);
#endif
_dic[fileoffset.first][vma] = Translator::mapped_type(vma+sz, section);
_addrs[vma] = fileoffset.first;
}
//----------------------------------------------------------------------------
std::map<std::string, mrw::StackTrace::Translator> mrw::StackTrace::_dic;
std::map<mrw::StackTrace::Translator::key_type, std::string>
mrw::StackTrace::_addrs;
std::map<std::string, mrw::StackTrace::AutoBfd> mrw::StackTrace::_bfd;
std::map<std::string, mrw::AutoPtrAry<asymbol*> > mrw::StackTrace::_syms;
#ifdef _MT
boost::recursive_mutex mrw::StackTrace::_mutex;
#endif
std::string mrw::StackTrace::_error;

View File

@@ -1,83 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#include <mrw/stacktrace.hxx>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
namespace mrw {
class StackTraceTest: public CppUnit::TestFixture {
public:
/// test if symbols are correctely evaluated
void StackTrace() {
bool init(mrw::StackTrace::createSymtable());
CPPUNIT_ASSERT_MESSAGE("createSymtable() failed! ERROR="
+mrw::StackTrace::error(),
init
||
mrw::StackTrace::error().find("/valgrind/")
!=std::string::npos);
mrw::StackTrace s; int l(__LINE__); std::string f(__FILE__);
std::stringstream ss;
ss<<f<<':'<<l;
std::string st(s);
mrw::StackTrace::BinFiles files(mrw::StackTrace::filename());
std::string msg("----------------------------------------\n"
"Stacktrace:\n-----------\n"+st+
"Files:\n------\n");
for (mrw::StackTrace::BinFiles::iterator it(files.begin());
it!=files.end(); ++it)
msg += " - \""+it->first+"\"\n";
msg += "----------------------------------------\n";
std::string::size_type pos(st.find("mrw::StackTraceTest::StackTrace()"));
CPPUNIT_ASSERT_MESSAGE("\"mrw::StackTraceTest::StackTrace()\""
" not found!\n"+msg, pos!=std::string::npos);
CPPUNIT_ASSERT_MESSAGE('"'+ss.str()+"\" not found!\n"+msg,
st.find(ss.str(), pos) < st.size());
CPPUNIT_ASSERT_MESSAGE("\"CppUnit::TestCaller<mrw::StackTraceTest>"
"::runTest()\" not found!\n"+msg,
st.find("CppUnit::TestCaller<mrw::StackTraceTest>"
"::runTest()")<st.size());
// The following test case does not work any more!
// Probable reason: The library has been stripped:
// > nm /usr/lib/libcppunit-1.10.so.2.0.0
// nm: /usr/lib/libcppunit-1.10.so.2.0.0: no symbols
// > file /usr/lib/libcppunit-1.10.so.2.0.0
// /usr/lib/libcppunit-1.10.so.2.0.0:
// ELF 32-bit LSB shared object, Intel 80386,
// version 1 (SYSV), stripped
//CPPUNIT_ASSERT_MESSAGE("\"CppUnit::TestCase::run\" not found!\n"+msg,
// st.find("CppUnit::TestCase::run")<st.size());
// The folowing test is probably wrong, because the syntax should be
// different:
// "???? ????:0"
// Anyway, with the problem of stripped libraries, as above, it doesn't
// pass anymore, if it is tested correctly...
//CPPUNIT_ASSERT_MESSAGE("\"????:0 ????\" should not be in stack!\n"+msg,
// st.find("????:0 ????")>=st.size());
}
CPPUNIT_TEST_SUITE(StackTraceTest);
CPPUNIT_TEST(StackTrace);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(StackTraceTest);
}
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,41 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.2 2004/12/14 20:21:21 marc
bugfix, now it works for empty lines
Revision 1.1 2004/10/13 11:18:33 marc
getline reads a whole line from a stream
*/
#include <stdext.hxx>
std::string mrw::getline(std::istream& is, char d) {
std::string s;
mrw::getline(is, s, d);
return s;
}
std::istream& mrw::getline(std::istream& is, std::string& s, char d) {
char buf[255];
char c;
s.clear();
do {
if (is) {
if (is.get(buf, 255, d)) s += buf;
is.clear(); // is.get fails if line is empty
if (is.get(c) && c!=d) s+=c;
}
} while (is.good() && !is.eof() && c!=d);
return is;
}

View File

@@ -1,266 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.3 2004/12/20 13:23:00 marc
new tests for string exceptions
Revision 1.2 2004/10/13 11:19:22 marc
remove stdout, print stack trace
Revision 1.1 2004/10/07 09:31:30 marc
new feature
*/
#include <mrw/string.hxx>
#include <mrw/list.hxx>
#include <mrw/vector.hxx>
#include <mrw/deque.hxx>
#include <mrw/set.hxx>
#include <mrw/map.hxx>
#include <mrw/multiset.hxx>
#include <mrw/multimap.hxx>
#include <mrw/stacktrace.hxx>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
class StdExtTest: public CppUnit::TestFixture {
public:
void StringConv() {
std::string s("Integer=");
int i(4);
CPPUNIT_ASSERT(s+mrw::string(i) == "Integer=4");
}
void StringShift() {
std::string s("Integer=");
int i(4);
CPPUNIT_ASSERT((s<<i<<" test "<<4<<(long)5<<" xx") == "Integer=4 test 45 xx");
int i2 = 0;
std::string s2, s3;
s>>s2>>s3>>i2;
CPPUNIT_ASSERT(s2=="Integer=4");
CPPUNIT_ASSERT(s3=="test");
CPPUNIT_ASSERT(i2==45);
CPPUNIT_ASSERT(s==" xx");
s2=""; s3="";
s>>s2;
CPPUNIT_ASSERT(s2=="xx");
CPPUNIT_ASSERT(s=="");
}
void StringAdd() {
std::string s;
s=s+(signed short)1+(signed int)2+(signed long)3+(signed char)'A'+
(unsigned short)1+(unsigned int)2+(unsigned long)3+(unsigned char)'A'+'c';
CPPUNIT_ASSERT(s=="1236512365c");
s=(signed short)-4+s;
s=(signed int)5+s;
s=(signed long)6+s;
s=(signed char)8+s;
s=(unsigned short)4+s;
s=(unsigned int)5+s;
s=(unsigned long)6+s;
s=(unsigned char)8+s;
s='a'+s;
CPPUNIT_ASSERT(s=="a8654865-41236512365c");
s+=(signed short)-4;
s+=(signed int)5 ;
s+=(signed long)6;
s+=(signed char)8 ;
s+=(unsigned short)4;
s+=(unsigned int)5 ;
s+=(unsigned long)6;
s+=(unsigned char)8 ;
s+='a';
CPPUNIT_ASSERT(s=="a8654865-41236512365c-45684568a");
}
void ListShift() {
std::list<int> l;
l<<1<<2<<3<<4<<5<<6<<7<<8;
int i1(0), i2(0), i3(0), i4(0);
l>>i1>>i2>>i3>>i4;
// now: i1==1 i2==2 i3==3 i4==4 l=={5, 6, 7, 8}
CPPUNIT_ASSERT(i1==1 && i2==2 && i3==3 && i4==4);
CPPUNIT_ASSERT(l.size()==4);
for (int i=0; i<4; (l.pop_front(), ++i)) {
CPPUNIT_ASSERT(l.front()==i+5);
}
bool exc(false);
try {
l>>i1;
} catch (mrw::length_error&) {
exc=true;
}
CPPUNIT_ASSERT(exc);
}
void VectorShift() {
std::vector<int> l;
l<<1<<2<<3<<4<<5<<6<<7<<8;
int i1(0), i2(0), i3(0), i4(0);
l>>i1>>i2>>i3>>i4;
// now: i1==1 i2==2 i3==3 i4==4 l=={5, 6, 7, 8}
CPPUNIT_ASSERT(i1==1 && i2==2 && i3==3 && i4==4);
CPPUNIT_ASSERT(l.size()==4);
for (int i=0; i<4; (l.erase(l.begin()), ++i)) {
CPPUNIT_ASSERT(l.front()==i+5);
}
bool exc(false);
try {
l>>i1;
} catch (mrw::length_error&) {
exc=true;
}
CPPUNIT_ASSERT(exc);
}
void DequeShift() {
std::deque<int> l;
l<<1<<2<<3<<4<<5<<6<<7<<8;
int i1(0), i2(0), i3(0), i4(0);
l>>i1>>i2>>i3>>i4;
// now: i1==1 i2==2 i3==3 i4==4 l=={5, 6, 7, 8}
CPPUNIT_ASSERT(i1==1 && i2==2 && i3==3 && i4==4);
CPPUNIT_ASSERT(l.size()==4);
for (int i=0; i<4; (l.erase(l.begin()), ++i)) {
CPPUNIT_ASSERT(l.front()==i+5);
}
bool exc(false);
try {
l>>i1;
} catch (mrw::length_error&) {
exc=true;
}
CPPUNIT_ASSERT(exc);
}
void SetShift() {
std::set<int> s;
bool exc(false);
try {
s<<1<<2<<3<<4<<5<<6<<7<<8<<8;
} catch (mrw::invalid_argument& e) {
mrw::StackTrace::createSymtable();
exc=true;
}
CPPUNIT_ASSERT(exc);
int i1(0), i2(0), i3(0), i4(0);
s>>i1>>i2>>i3>>i4;
// now: i1==1 i2==2 i3==3 i4==4 s=={5, 6, 7, 8}
CPPUNIT_ASSERT(i1==1 && i2==2 && i3==3 && i4==4);
CPPUNIT_ASSERT(s.size()==4);
for (int i=0; i<4; ++i) {
CPPUNIT_ASSERT(s.find(i+5)!=s.end());
}
s.erase(s.begin(), s.end());
exc=false;
try {
s>>i1;
} catch (mrw::length_error&) {
exc=true;
}
CPPUNIT_ASSERT(exc);
}
void MapShift() {
std::map<int, std::string> s;
bool exc(false);
try {
s<<std::make_pair(1, std::string("one"))
<<std::make_pair(2, std::string("two"))
<<std::make_pair(2, std::string("two"));
} catch (mrw::invalid_argument& e) {
exc=true;
}
CPPUNIT_ASSERT(exc);
std::pair<int, std::string> i1, i2;
s>>i1>>i2;
// now: i1==1 i2==2 i3==3 i4==4 s=={5, 6, 7, 8}
CPPUNIT_ASSERT(i1==std::make_pair(1, std::string("one")) &&
i2==std::make_pair(2, std::string("two")));
CPPUNIT_ASSERT(s.size()==0);
exc=false;
try {
s>>i1;
} catch (mrw::length_error&) {
exc=true;
}
CPPUNIT_ASSERT(exc);
}
void MultisetShift() {
std::multiset<int> s;
s<<1<<2<<3<<4<<5<<6<<7<<8<<9;
int i1(0), i2(0), i3(0), i4(0);
s>>i1>>i2>>i3>>i4;
// now: i1==1 i2==2 i3==3 i4==4 s=={5, 6, 7, 8}
CPPUNIT_ASSERT(i1==1 && i2==2 && i3==3 && i4==4);
CPPUNIT_ASSERT(s.size()==5);
for (int i=0; i<5; ++i) {
CPPUNIT_ASSERT(s.find(i+5)!=s.end());
}
s.erase(s.begin(), s.end());
bool exc(false);
try {
s>>i1;
} catch (mrw::length_error&) {
exc=true;
}
CPPUNIT_ASSERT(exc);
}
void MultimapShift() {
std::multimap<int, std::string> s;
s<<std::make_pair(1, std::string("one"))
<<std::make_pair(2, std::string("two"))
<<std::make_pair(2, std::string("two"));
std::pair<int, std::string> i1, i2;
s>>i1>>i2;
// now: i1==1 i2==2 i3==3 i4==4 s=={5, 6, 7, 8}
CPPUNIT_ASSERT(i1==std::make_pair(1, std::string("one")) &&
i2==std::make_pair(2, std::string("two")));
CPPUNIT_ASSERT(s.size()==1);
s>>i1;
CPPUNIT_ASSERT(i1==std::make_pair(2, std::string("two")));
bool exc(false);
try {
s>>i1;
} catch (mrw::length_error&) {
exc=true;
}
CPPUNIT_ASSERT(exc);
}
void StringException1() {
std::string s("Hello World");
int hello;
s>>hello; // not an int, exception expected
}
void StringException2() {
std::string s("Hello World");
mrw::to<int>(s); // not an int, exception expected
}
CPPUNIT_TEST_SUITE(StdExtTest);
CPPUNIT_TEST(StringConv);
CPPUNIT_TEST(StringShift);
CPPUNIT_TEST(StringAdd);
CPPUNIT_TEST(ListShift);
CPPUNIT_TEST(VectorShift);
CPPUNIT_TEST(DequeShift);
CPPUNIT_TEST(SetShift);
CPPUNIT_TEST(MapShift);
CPPUNIT_TEST(MultisetShift);
CPPUNIT_TEST(MultimapShift);
CPPUNIT_TEST_EXCEPTION(StringException1, mrw::invalid_argument);
CPPUNIT_TEST_EXCEPTION(StringException2, mrw::invalid_argument);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(StdExtTest);
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1,49 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890
*/
#include <mrw/string.hxx>
#include <mrw/list.hxx>
#include <algorithm>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
class StringTest: public CppUnit::TestFixture {
public:
void Join() {
std::list<std::string> l;
l<<"Hello"<<"World"<<"here"<<"I"<<"am";
CPPUNIT_ASSERT(mrw::join(l)=="Hello World here I am");
}
void Split() {
std::string text("Hello World here I am");
std::list<std::string> a(mrw::split(text)), b;
b<<"Hello"<<"World"<<"here"<<"I"<<"am";
CPPUNIT_ASSERT(equal(a.begin(), a.end(), b.begin()));
}
CPPUNIT_TEST_SUITE(StringTest);
CPPUNIT_TEST(Join);
CPPUNIT_TEST(Split);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(StringTest);
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}

View File

@@ -1 +0,0 @@
Hallo Welt

View File

@@ -1,74 +0,0 @@
/** @file
$Id$
$Date$
$Author$
@copy &copy; Marc W&auml;ckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
Revision 1.2 2005/01/07 00:35:17 marc
initial version
Revision 1.1 2004/12/17 16:26:58 marc
initial version
*/
#include <mrw/tokenizer.hxx>
#include <mrw/list.hxx>
#include <algorithm>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
class TokenizerTest: public CppUnit::TestFixture {
public:
void CheckNonGreedy() {
const std::string aux[] = {"first", "second", "third", "", "fifth"};
std::list<std::string> a(aux, aux+sizeof(aux)/sizeof(std::string)), b;
mrw::Tokenizer token("first,second,third,,fifth", false, ",");
while (token) b<<token();
CPPUNIT_ASSERT(equal(a.begin(), a.end(), b.begin()));
}
void CheckGreedy() {
const std::string aux[] = {"Hello", "world", "here", "I", "am"};
std::list<std::string> a(aux, aux+sizeof(aux)/sizeof(std::string)), b;
mrw::Tokenizer token("Hello world, here I am!", true, " \t\n,.?!");
while (token) b<<token();
CPPUNIT_ASSERT(equal(a.begin(), a.end(), b.begin()));
}
void CheckReset() {
const std::string aux[] = {"first", "second", "third", "", "fifth"};
std::list<std::string> a(aux, aux+sizeof(aux)/sizeof(std::string)), b;
mrw::Tokenizer token("first,second,third,,fifth", false, ",");
while (token) b<<token();
CPPUNIT_ASSERT(equal(a.begin(), a.end(), b.begin()));
const std::string aux2[] = {"a", "b", "c", "d", "e"};
std::list<std::string> a2(aux2, aux2+sizeof(aux2)/sizeof(std::string)),
b2, b3;
token.reset("a,b,c,d,e");
while (token) b2<<token();
CPPUNIT_ASSERT(equal(a2.begin(), a2.end(), b2.begin()));
token.reset();
while (token) b3<<token();
CPPUNIT_ASSERT(equal(a2.begin(), a2.end(), b3.begin()));
}
CPPUNIT_TEST_SUITE(TokenizerTest);
CPPUNIT_TEST(CheckNonGreedy);
CPPUNIT_TEST(CheckGreedy);
CPPUNIT_TEST(CheckReset);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(TokenizerTest);
int main() {
CppUnit::TextUi::TestRunner runner;
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
return runner.run() ? 0 : 1;
}