MOAB: Mesh Oriented datABase
(version 5.4.1)
|
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