Inferno  0.2
trace.cpp
Go to the documentation of this file.
00001 #include "trace.hpp"
00002 #include <boost/assert.hpp>
00003 #include <stdarg.h>
00004 #include <string.h>
00005 #include <malloc.h>
00006 #include <unistd.h>
00007 
00008 bool Tracer::continuation = false;
00009 bool Tracer::enable = false; ///< call Tracer::Enable(true) to begin tracing
00010 string Tracer::Descend::pre;
00011 string Tracer::Descend::last_traced_pre, Tracer::Descend::leftmost_pre;
00012 
00013 void Tracer::Descend::Indent()
00014 {
00015     // Detect cases where the indent level dropped and then went up again, without
00016     // any actual traces at the lower indent level. Put a "<" in at the level it
00017     // dropped to.
00018     if( leftmost_pre.size() < last_traced_pre.size() && leftmost_pre.size() < pre.size() )
00019         fprintf(stderr, "%s<\n", leftmost_pre.c_str());
00020     last_traced_pre = leftmost_pre = pre;
00021     fprintf(stderr, "%s", pre.c_str());
00022 }
00023 
00024 inline void InfernoAbort()
00025 {
00026     fflush( stderr ); 
00027 
00028     // The C library provides abort(), but I'm not getting a stack dump under cygwin
00029     (*(int*)-1)++; 
00030 }
00031 
00032 Tracer::Tracer( const char *f, int l, const char *fu, Flags fl, char const *c ) :
00033     file( f ),
00034     line( l ),
00035     function( fu ),
00036     flags( fl )
00037 {
00038     // If we're going to abort, get this out first, then usual trace message if required as a continuation
00039     if( flags & ABORT )
00040     {
00041         EndContinuation();
00042         fprintf( stderr, "\n");
00043         Descend::Indent();
00044         fprintf( stderr, "----Assertion failed: %s\n", c);
00045         Descend::Indent();
00046         fprintf( stderr, "----%s:%d in %s()\n", file, line, function);
00047         continuation = true;
00048     }
00049 }
00050 
00051 Tracer::~Tracer()
00052 {
00053     if( flags & ABORT )
00054     {
00055         EndContinuation();
00056         InfernoAbort();
00057     }
00058 }
00059 
00060 Tracer &Tracer::operator()()
00061 {
00062     if( (flags & DISABLE) || !(enable || (flags & FORCE)) )
00063         return *this;
00064  
00065     EndContinuation();
00066     Descend::Indent();
00067     fprintf( stderr, "----%s:%d in %s()\n", file, line, function);
00068     
00069     return *this;
00070 }
00071 
00072 Tracer &Tracer::operator()(const char *fmt, ...)
00073 {
00074     if( (flags & DISABLE) || !(enable || (flags & FORCE)) )
00075         return *this;
00076 
00077     va_list vl;
00078     va_start( vl, fmt );
00079     if( !continuation ) 
00080     {
00081       Descend::Indent();
00082         fprintf( stderr, "----%s:%d in %s()\n", file, line, function);
00083         Descend::Indent();
00084     }
00085     vfprintf( stderr, fmt, vl );
00086     va_end( vl );
00087     
00088     continuation = (fmt[strlen(fmt)-1]!='\n');
00089     return *this;
00090 }
00091 
00092 Tracer &Tracer::operator()(const string &s)
00093 {    
00094     return operator()("%s", s.c_str());
00095 }
00096 
00097 void Tracer::EndContinuation()
00098 {
00099     if( continuation ) 
00100     {
00101         fprintf(stderr, "\n");
00102         continuation = false;
00103     }   
00104 }
00105 
00106 void Tracer::Enable( bool e )
00107 {
00108     enable = e;
00109 }
00110 
00111 
00112 // Make BOOST_ASSERT work (we don't use them but other code might)
00113 void boost::assertion_failed(char const * expr, char const * function, char const * file, long line)
00114 {
00115     Tracer::EndContinuation();
00116     Tracer( file, line, function, Tracer::FORCE )( "Assertion failed: %s\n\n", expr );
00117     InfernoAbort();
00118 }
00119 
00120