middle of porting; unstable, don't checkout; refs #1
This commit is contained in:
138
src/mrw/arg.cxx
138
src/mrw/arg.cxx
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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++ / 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 (...) {}
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//@}
|
||||
@@ -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 © Marc Wä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 (...) {}
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
|
||||
}
|
||||
@@ -1,193 +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/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;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
#! /bin/bash
|
||||
|
||||
test -z "`diff $srcdir/configfile2.ini $srcdir/configfile.ini.result`" \
|
||||
&& rm configfile2.ini
|
||||
@@ -1,72 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +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/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
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
}
|
||||
557
src/mrw/exec.cxx
557
src/mrw/exec.cxx
@@ -1,557 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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);
|
||||
@@ -1,133 +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/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;
|
||||
}
|
||||
@@ -1,223 +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/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;
|
||||
|
||||
//@}
|
||||
//@}
|
||||
}
|
||||
@@ -1,244 +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/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;
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,387 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
@@ -1,83 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
Hallo Welt
|
||||
@@ -1,74 +0,0 @@
|
||||
/** @file
|
||||
|
||||
$Id$
|
||||
|
||||
$Date$
|
||||
$Author$
|
||||
|
||||
@copy © Marc Wä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;
|
||||
}
|
||||
Reference in New Issue
Block a user