MOAB: Mesh Oriented datABase  (version 5.4.1)
ErrorOutput.cpp
Go to the documentation of this file.
00001 #include "ErrorOutput.hpp"
00002 #include "moab/MOABConfig.h"
00003 
00004 #include <iostream>
00005 #include <cstring>
00006 #include <algorithm>
00007 #include <cassert>
00008 
00009 #ifdef MOAB_HAVE_MPI
00010 #include "moab_mpi.h"
00011 #endif
00012 
00013 namespace moab
00014 {
00015 
00016 class FILEErrorStream : public ErrorOutputStream
00017 {
00018   private:
00019     FILE* filePtr;
00020 
00021   public:
00022     FILEErrorStream( FILE* filep ) : filePtr( filep ) {}
00023     void println( int rank, const char* str );
00024     void println( const char* str );
00025 };
00026 
00027 void FILEErrorStream::println( int rank, const char* str )
00028 {
00029     fprintf( filePtr, "[%d]MOAB ERROR: %s\n", rank, str );
00030     fflush( filePtr );
00031 }
00032 
00033 void FILEErrorStream::println( const char* str )
00034 {
00035     fprintf( filePtr, "MOAB ERROR: %s\n", str );
00036     fflush( filePtr );
00037 }
00038 
00039 class CxxErrorStream : public ErrorOutputStream
00040 {
00041   private:
00042     std::ostream& outStr;
00043 
00044   public:
00045     CxxErrorStream( std::ostream& str ) : outStr( str ) {}
00046     void println( int rank, const char* str );
00047     void println( const char* str );
00048 };
00049 
00050 void CxxErrorStream::println( int rank, const char* str )
00051 {
00052     outStr << "[" << rank << "]MOAB ERROR: " << str << std::endl;
00053     outStr.flush();
00054 }
00055 
00056 void CxxErrorStream::println( const char* str )
00057 {
00058     outStr << "MOAB ERROR: " << str << std::endl;
00059     outStr.flush();
00060 }
00061 
00062 ErrorOutput::ErrorOutput( FILE* impl ) : outputImpl( new FILEErrorStream( impl ) ), mpiRank( -1 )
00063 {
00064     lineBuffer.reserve( 1024 );
00065 }
00066 
00067 ErrorOutput::ErrorOutput( std::ostream& str ) : outputImpl( new CxxErrorStream( str ) ), mpiRank( -1 )
00068 {
00069     lineBuffer.reserve( 1024 );
00070 }
00071 
00072 ErrorOutput::~ErrorOutput()
00073 {
00074     if( !lineBuffer.empty() )
00075     {
00076         lineBuffer.push_back( '\n' );
00077         process_line_buffer();
00078     }
00079 
00080     if( NULL != outputImpl )
00081     {
00082         delete outputImpl;
00083         outputImpl = NULL;
00084     }
00085 }
00086 
00087 void ErrorOutput::use_world_rank()
00088 {
00089 #ifdef MOAB_HAVE_MPI
00090     int flag1;
00091     MPI_Initialized( &flag1 );
00092     int flag2;
00093     MPI_Finalized( &flag2 );
00094     if( flag1 && !flag2 ) MPI_Comm_rank( MPI_COMM_WORLD, &mpiRank );
00095 #endif
00096 }
00097 
00098 void ErrorOutput::print_real( const char* buffer )
00099 {
00100     lineBuffer.insert( lineBuffer.end(), buffer, buffer + strlen( buffer ) );
00101     process_line_buffer();
00102 }
00103 
00104 void ErrorOutput::print_real( const std::string& str )
00105 {
00106     lineBuffer.insert( lineBuffer.end(), str.begin(), str.end() );
00107     process_line_buffer();
00108 }
00109 
00110 void ErrorOutput::print_real( const char* fmt, va_list args1, va_list args2 )
00111 {
00112     size_t idx = lineBuffer.size();
00113 #ifdef MOAB_HAVE_VSNPRINTF
00114     // try once with remaining space in buffer
00115     lineBuffer.resize( lineBuffer.capacity() );
00116     unsigned size = vsnprintf( &lineBuffer[idx], lineBuffer.size() - idx, fmt, args1 );
00117     ++size;  // trailing null
00118     // if necessary, increase buffer size and retry
00119     if( size > ( lineBuffer.size() - idx ) )
00120     {
00121         lineBuffer.resize( idx + size );
00122         size = vsnprintf( &lineBuffer[idx], lineBuffer.size() - idx, fmt, args2 );
00123         ++size;  // trailing null
00124     }
00125 #else
00126     // Guess how much space might be required.
00127     // If every character is a format code then there are len/3 format codes.
00128     // Guess a random large value of num_chars characters per formatted argument.
00129     const unsigned num_chars = 180;
00130     unsigned exp_size        = ( num_chars / 3 ) * strlen( fmt );
00131     lineBuffer.resize( idx + exp_size );
00132     unsigned size = vsprintf( &lineBuffer[idx], fmt, args1 );
00133     ++size;  // trailing null
00134     // check if we overflowed the buffer
00135     if( size > exp_size )
00136     {
00137         // crap!
00138         fprintf( stderr, "ERROR: Buffer overflow at %s:%d\n", __FILE__, __LINE__ );
00139         lineBuffer.resize( idx + exp_size );
00140         size = vsprintf( &lineBuffer[idx], fmt, args2 );
00141         ++size;  // trailing null
00142     }
00143 #endif
00144 
00145     // less one because we don't want the trailing '\0'
00146     lineBuffer.resize( idx + size - 1 );
00147     process_line_buffer();
00148 }
00149 
00150 void ErrorOutput::process_line_buffer()
00151 {
00152     size_t last_idx = 0;
00153     std::vector< char >::iterator i;
00154     for( i = std::find( lineBuffer.begin(), lineBuffer.end(), '\n' ); i != lineBuffer.end();
00155          i = std::find( i, lineBuffer.end(), '\n' ) )
00156     {
00157         *i = '\0';
00158         if( have_rank() )
00159             outputImpl->println( get_rank(), &lineBuffer[last_idx] );
00160         else
00161             outputImpl->println( &lineBuffer[last_idx] );
00162         ++i;
00163         last_idx = i - lineBuffer.begin();
00164     }
00165 
00166     if( last_idx )
00167     {
00168         i = std::copy( lineBuffer.begin() + last_idx, lineBuffer.end(), lineBuffer.begin() );
00169         lineBuffer.erase( i, lineBuffer.end() );
00170     }
00171 }
00172 
00173 }  // namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines