/** @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.cpp - 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 */ #ifndef __MRW_SIMPLETRACE_HPP__ #define __MRW_SIMPLETRACE_HPP__ #include <iostream> #include <iomanip> #include <string> /** @defgroup SimpleTrace Simple Tracing (for temporary debugging) @pre #include <mrw/simpletrace.hpp> Here is a simple tracing to @c std::cout mechanism for temporary debugging and simple testing purposes. Might be useful when experimenting and exploring new C++ language constructs. Please note that you can only trace in methods and functions that start with @c METHOD respectively @c FUNCTION. Please note that you should not use this simple mechanism for real projects, only for your experiments! For your work, use <a href="http://logging.apache.org/log4cxx">log4cxx</a>! The trace of the following code: @code #include <mrw/simpletrace.hpp> void fn(int i=0) { FUNCTION; // trace entry and exit if (!i) TRACE("Hello World, this is a nice text!"); if (i<4) fn(++i); } class A { public: A() { NO_TRACE; // don't trace in constructor method(); // not traced } void method() { METHOD; // trace entry and exit CALL(fn()); // trace before call fn(); } }; int main(int, char**) { FUNCTION; CALL(A().method()); A().method(); TRACE("No more trace:"); TRACE_OFF; A().method(); TRACE_ON; TRACE("Back again"); return 0; } @endcode Produces this output: @verbatim tmp.cpp:20 0: \ main tmp.cpp:21 0: -> A().method() tmp.cpp:14 0xbffff10f: \ method tmp.cpp:15 0xbffff10f: -> fn() tmp.cpp:3 0: \ fn tmp.cpp:4 0: **** Hello World, this is a nice text! **** tmp.cpp:3 0: \ fn tmp.cpp:3 0: \ fn tmp.cpp:3 0: \ fn tmp.cpp:3 0: \ fn tmp.cpp:3 0: / fn tmp.cpp:3 0: / fn tmp.cpp:3 0: / fn tmp.cpp:3 0: / fn tmp.cpp:3 0: / fn tmp.cpp:14 0xbffff10f: / method tmp.cpp:23 0: **** No more trace: **** tmp.cpp:27 0: **** Back again **** tmp.cpp:20 0: / main @endverbatim */ //@{ #ifndef __GNUG__ /// Declare method entrance, place as first line in method. #define METHOD(name) mrw::FnTrace fnTrace(this, #name, __FILE__, __LINE__) /// Declare function entrance, place as first line in function. #define FUNCTION(name) mrw::FnTrace fnTrace(0, #name, __FILE__, __LINE__) #else /// Declare method entrance, place as first line in method. /// GNU g++ knows the method name. #define METHOD mrw::FnTrace fnTrace(this, __FUNCTION__, __FILE__, __LINE__) /// Declare function entrance, place as first line in function. /// GNU g++ knows the method name. #define FUNCTION mrw::FnTrace fnTrace(0, __FUNCTION__, __FILE__, __LINE__) #endif /// Document the call of another method (before you call it). #define CALL(name) fnTrace.call(#name, __FILE__, __LINE__) /// Trace an arbitrary text. #define TRACE(text) fnTrace.trace(text, __FILE__, __LINE__) /// Turn all tracing off (from here on). #define TRACE_OFF mrw::FnTrace::off() /// Turn all tracing off (from here on). #define TRACE_ON mrw::FnTrace::on() /// Don't trace in this scope (from here on). #define NO_TRACE mrw::NoTrace noTrace; namespace mrw { class FnTrace { public: FnTrace(const void* addr, const std::string& name, const std::string& file, unsigned long line) throw(): _addr(addr), _name(name), _file(file), _line(line) { if (_off==0) std::cout<<std::setw(15)<<_file<<':'<<std::setiosflags(std::ios::left) <<std::setw(5)<<_line<<std::resetiosflags(std::ios::left)<<' ' <<std::hex<<std::setw(15)<<_addr<<": "<<std::dec <<std::setw(2+_level)<<std::setfill(' ')<<"\\ " <<_name<<std::endl; ++_level; } ~FnTrace() throw() { --_level; if (_off==0) std::cout<<std::setw(15)<<_file<<':'<<std::setiosflags(std::ios::left) <<std::setw(5)<<_line<<std::resetiosflags(std::ios::left)<<' ' <<std::hex<<std::setw(15)<<_addr<<": "<<std::dec <<std::setw(2+_level)<<std::setfill(' ')<<"/ "<<_name <<std::endl; } void call(const std::string& name, const std::string& file, unsigned long line) throw() { if (_off==0) std::cout<<std::setw(15)<<file<<':'<<std::setiosflags(std::ios::left) <<std::setw(5)<<line<<std::resetiosflags(std::ios::left)<<' ' <<std::hex<<std::setw(15)<<_addr<<": "<<std::dec <<std::setw(4+_level)<<std::setfill(' ')<<" -> "<<name <<std::endl; } void trace(const std::string& text, const std::string& file, unsigned long line) throw() { if (_off==0) std::cout<<std::setw(15)<<file<<':'<<std::setiosflags(std::ios::left) <<std::setw(5)<<line<<std::resetiosflags(std::ios::left)<<' ' <<std::hex<<std::setw(15)<<_addr<<": "<<std::dec <<std::setw(4+_level)<<std::setfill(' ')<<" **** "<<text <<" **** "<<std::endl; } static void off() throw() { ++_off; } static void on() throw() { if (_off>0) --_off; } private: const void* _addr; const std::string _name; const std::string _file; unsigned long _line; static unsigned int _level; static unsigned int _off; }; unsigned int FnTrace::_level(0); unsigned int FnTrace::_off(0); class NoTrace { public: NoTrace() throw() {TRACE_OFF;} ~NoTrace() throw() {TRACE_ON;} }; } //@} #endif