TraceFct.cc

00001 // --8<--8<--8<--8<--
00002 //
00003 // Copyright (C) 2006-2012 Smithsonian Astrophysical Observatory
00004 //
00005 // This file is part of tracefctxx
00006 //
00007 // tracefctxx is free software: you can redistribute it and/or modify
00008 // it under the terms of the GNU General Public License as published by
00009 // the Free Software Foundation, either version 3 of the License, or (at
00010 // your option) any later version.
00011 //
00012 // This program is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 //
00020 // -->8-->8-->8-->8--
00021 
00022 #include <iostream>
00023 #include <fstream>
00024 #include <cstring>
00025 #include <unistd.h>
00026 using namespace std;
00027 
00028 #include "TraceFct.h"
00029 
00030 #define NUM_BLANK_SPACES "   "
00031 
00032 bool    TraceFct::print_upon_enter_and_exit(false);
00033 int     TraceFct::stack_level_to_print(-1);
00034 string  TraceFct::progname("UNKNOWN PROGRAM");
00035 string  TraceFct::prefix = TraceFct::init_prefix();
00036 char    TraceFct::outbuf[8192];
00037 ostream* TraceFct::ostr = &cerr;
00038 list<string> TraceFct::function_stack;
00039 
00040 char *
00041 TraceFct::init_prefix( void )
00042 {
00043   sprintf(outbuf, "# %d: %s: ", getpid(), progname.c_str() );
00044   return outbuf;
00045 }
00046 
00047 //====================================================================//
00048 
00049 
00051 
00077 TraceFct::TraceFct( string prog_name, bool print_it, int num_fct_to_print ) 
00078 {
00079 
00080   progname = prog_name;
00081 
00082   print_upon_enter_and_exit = print_it;
00083 
00084   stack_level_to_print = num_fct_to_print;
00085 
00086   function_stack.clear();
00087 
00088   ostr = &cerr;
00089 
00090   prefix = init_prefix( );
00091 }
00092 
00094 
00103 TraceFct::TraceFct(string& name)
00104 {
00105   function_stack.push_back( name );
00106 
00107   if (print_upon_enter_and_exit)
00108     message( "[%2d] %s: entering\n", function_stack.size(), 
00109              function_stack.back().c_str() );
00110 }
00111 
00119 TraceFct::TraceFct(const char* name)
00120 {
00121   function_stack.push_back( name );
00122 
00123   if (print_upon_enter_and_exit)
00124     message( "[%2d] %s: entering\n", function_stack.size(), 
00125              function_stack.back().c_str() );
00126 }
00127 
00129 
00135 TraceFct::~TraceFct( )
00136 {
00137   // if the function stack is empty, we must be at the top level;
00138   // nothing to do.
00139   if ( ! function_stack.empty() )
00140   {
00141     if (print_upon_enter_and_exit)
00142     {
00143       message( "[%2d] %s: leaving\n", function_stack.size(), 
00144                function_stack.back().c_str() );
00145     }
00146 
00147     function_stack.pop_back();
00148   }
00149 
00150   else
00151   {
00152     // close the output stream
00153     if ( &cerr != ostr )
00154       delete ostr;
00155   }
00156 }
00157 
00158 //====================================================================//
00159 
00160 
00176 void
00177 TraceFct::vprint(
00178   bool print_nl,
00179   const char *format,
00180   va_list args
00181   )
00182 {
00183   char *start, *end;
00184 
00185   vsprintf(outbuf, format, args);
00186 
00187   // seeking to the end of a non-seekable stream (e.g. cerr)
00188   // fails. don't really care, so ignore any failure
00189   (*ostr).seekp(0, std::ios::end);
00190   if ( (*ostr).fail() )
00191       (*ostr).clear( (*ostr).rdstate() & ~std::ios::failbit );
00192 
00193   for ( start = outbuf ; end = strchr( start, '\n' ) ; start = end )
00194   {
00195     char save;
00196     save = *++end;
00197     *end = '\0';
00198 
00199     if ( ostr == &cerr )
00200       *ostr << prefix;
00201 
00202     *ostr << start;
00203 
00204     *end = save;
00205   }
00206 
00207   if ( *start )
00208   {
00209     if ( ostr == &cerr )
00210       *ostr << prefix;
00211 
00212     *ostr << start;
00213   }
00214 
00215   if (  print_nl && '\n' != outbuf[strlen(outbuf)-1] )
00216     *ostr << '\n';
00217 
00218   (*ostr).flush();
00219 
00220 }
00221 
00222 
00232 void
00233 TraceFct::print(
00234   bool print_nl,
00235   const char *format,
00236   ...
00237   )
00238 {
00239   va_list args;
00240   va_start( args, format );
00241   vprint( print_nl, format, args );
00242   va_end(args );
00243 }
00244 
00254 void
00255 TraceFct::print(
00256   bool print_nl,
00257   Exception& ex
00258   )
00259 {
00260   deque<string>::const_iterator begin = ex.begin();
00261   deque<string>::const_iterator end   = ex.end();
00262 
00263     while( begin != end )
00264       print( print_nl, (*begin++).c_str() );
00265 }
00266 
00267 
00268 //====================================================================//
00269 
00277 void
00278 TraceFct::dump_stack()
00279 {
00280 
00281   message( "Stack:\n" );
00282 
00283   unsigned max_level = stack_level_to_print > -1 ?
00284               stack_level_to_print : function_stack.size();
00285 
00286   if ( function_stack.size() < max_level )
00287     max_level = function_stack.size();
00288 
00289   list<string>::iterator begin = function_stack.begin();
00290   list<string>::iterator   end = function_stack.end();
00291   advance( begin, function_stack.size() - max_level );
00292 
00293   int depth = function_stack.size();
00294   while( begin != end )
00295   {
00296     end--;
00297     message( " [%2d] %s\n", depth, end->c_str() );
00298     depth--;
00299   }
00300 
00301   if ( stack_level_to_print == -1 ||
00302        max_level > function_stack.size() )
00303     message( " [ 0] <TOP>\n");
00304 }
00305 
00306 
00307 //====================================================================//
00308 
00319 void
00320 TraceFct::vexit_print(
00321   const char *format,
00322   va_list args
00323 )
00324 {
00325   vprint( true, format, args );
00326 
00327   dump_stack(  );
00328 }
00329 
00330 
00331 //====================================================================//
00332 
00333 
00347 
00348 // doxygen braindamage; can't pull inlines from header file into
00349 // a member group
00365 void
00366 TraceFct::exit
00367 (
00368   int exit_code,
00369   const char *format,           
00370   ...
00371 )
00372 {
00373   va_list args;
00374 
00375   if ( ostr != &cerr )
00376   {
00377     va_start(args, format);
00378     vexit_print( format, args );
00379     va_end(args);
00380     delete ostr;
00381   }
00382 
00383   ostr = &cerr;
00384 
00385   va_start(args, format);
00386   vexit_print( format, args );
00387   va_end(args);
00388   
00389   std::exit(exit_code);
00390 }
00391 
00402 void
00403 TraceFct::exit
00404 (
00405   int exit_code,
00406   Exception& ex
00407 )
00408 {
00409   deque<string>::const_iterator begin = ex.begin();
00410   deque<string>::const_iterator end   = ex.end();
00411   
00412   if ( ostr != &cerr ){
00413     print( true, ex );
00414     delete ostr;
00415   }
00416 
00417   ostr = &cerr;
00418 
00419   print( true, ex );
00420   
00421   dump_stack();
00422   std::exit(exit_code);
00423   
00424 }
00425 
00426 // doxygen braindamage; can't pull inlines from header file into a member group
00450 void
00451 TraceFct::die
00452 (
00453   const char *format,           
00454   ...
00455 )
00456 {
00457   va_list args;
00458 
00459   if ( ostr != &cerr )
00460   {
00461     va_start(args, format);
00462     vexit_print( format, args );
00463     va_end(args);
00464     delete ostr;
00465   }
00466 
00467   ostr = &cerr;
00468 
00469   va_start(args, format);
00470   vexit_print( format, args );
00471   va_end(args);
00472   
00473   std::exit(EXIT_FAILURE);
00474 }
00475 
00476 
00478 
00479 //====================================================================//
00480 
00496 
00497 // doxygen braindamage; can't pull inlines from header file into
00498 // a member group
00519 void
00520 TraceFct::message
00521 (
00522   const char *format,           /* a printf style string */
00523   ...                   /* objects to print */
00524 )
00525 {
00526   va_list args;
00527 
00528   va_start(args, format);
00529 
00530   vprint( false, format, args );
00531 
00532   va_end(args);
00533 }
00534 
00535 
00547 void
00548 TraceFct::vmessage
00549 (
00550   const char *format,
00551   va_list args          /* objects to print */
00552 )
00553 {
00554   vprint( false, format, args );
00555 }
00556 
00557 
00558 // doxygen braindamage; can't pull inlines from header file into
00559 // a member group
00578 
00579 //====================================================================//
00580 
00581 
00585 
00603 void
00604 TraceFct::open(
00605   const string& file    /* the file to which messages are to be written */
00606   )
00607 {
00608   ostream* new_ostr;
00609 
00610   if ( file != "stderr" )
00611   {
00612     try 
00613     {
00614       new_ostr = new ofstream( file.c_str() );
00615 
00616       if ( ! *new_ostr )
00617       {
00618         cerr << prefix << "unable to open TraceFct output stream `" 
00619              << file << '\'' << endl;
00620         std::exit(1);
00621       }
00622     }
00623     catch (...)
00624     {
00625       // dunno what happend but it wasn't good!
00626       cerr << prefix 
00627            << "error creating TraceFct output stream object for `" 
00628            << file << '\'' << endl;
00629       std::exit(1);
00630     }
00631 
00632   }
00633   else
00634     new_ostr = &cerr;
00635 
00636   if ( ostr != &cerr )
00637     delete ostr;
00638 
00639   ostr = new_ostr;
00640 }
00641 
00651 void
00652 TraceFct::close( void )
00653 {
00654   if ( &cerr != ostr )
00655   {
00656     delete ostr;
00657     ostr = &cerr;
00658   }
00659 }
00660 
00661 
00663 
00664 //====================================================================//