1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "ErrorOutput.hpp"
#include "moab/MOABConfig.h"

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cassert>

#ifdef MOAB_HAVE_MPI
#include "moab_mpi.h"
#endif

namespace moab
{

class FILEErrorStream : public ErrorOutputStream
{
  private:
    FILE* filePtr;

  public:
    FILEErrorStream( FILE* filep ) : filePtr( filep ) {}
    void println( int rank, const char* str );<--- Function in derived class
    void println( const char* str );<--- Function in derived class
};

void FILEErrorStream::println( int rank, const char* str )
{
    fprintf( filePtr, "[%d]MOAB ERROR: %s\n", rank, str );
    fflush( filePtr );
}

void FILEErrorStream::println( const char* str )
{
    fprintf( filePtr, "MOAB ERROR: %s\n", str );
    fflush( filePtr );
}

class CxxErrorStream : public ErrorOutputStream
{
  private:
    std::ostream& outStr;

  public:
    CxxErrorStream( std::ostream& str ) : outStr( str ) {}
    void println( int rank, const char* str );<--- Function in derived class
    void println( const char* str );<--- Function in derived class
};

void CxxErrorStream::println( int rank, const char* str )
{
    outStr << "[" << rank << "]MOAB ERROR: " << str << std::endl;
    outStr.flush();
}

void CxxErrorStream::println( const char* str )
{
    outStr << "MOAB ERROR: " << str << std::endl;
    outStr.flush();
}

ErrorOutput::ErrorOutput( FILE* impl ) : outputImpl( new FILEErrorStream( impl ) ), mpiRank( -1 )
{
    lineBuffer.reserve( 1024 );
}

ErrorOutput::ErrorOutput( std::ostream& str ) : outputImpl( new CxxErrorStream( str ) ), mpiRank( -1 )<--- Class 'ErrorOutput' does not have a copy constructor which is recommended since it has dynamic memory/resource allocation(s).<--- Class 'ErrorOutput' does not have a operator= which is recommended since it has dynamic memory/resource allocation(s).
{
    lineBuffer.reserve( 1024 );
}

ErrorOutput::~ErrorOutput()
{
    if( !lineBuffer.empty() )
    {
        lineBuffer.push_back( '\n' );
        process_line_buffer();
    }

    if( NULL != outputImpl )
    {
        delete outputImpl;
        outputImpl = NULL;
    }
}

void ErrorOutput::use_world_rank()
{
#ifdef MOAB_HAVE_MPI
    int flag1;
    MPI_Initialized( &flag1 );
    int flag2;
    MPI_Finalized( &flag2 );
    if( flag1 && !flag2 ) MPI_Comm_rank( MPI_COMM_WORLD, &mpiRank );
#endif
}

void ErrorOutput::print_real( const char* buffer )
{
    lineBuffer.insert( lineBuffer.end(), buffer, buffer + strlen( buffer ) );
    process_line_buffer();
}

void ErrorOutput::print_real( const std::string& str )
{
    lineBuffer.insert( lineBuffer.end(), str.begin(), str.end() );
    process_line_buffer();
}

void ErrorOutput::print_real( const char* fmt, va_list args1, va_list args2 )
{
    size_t idx = lineBuffer.size();
#ifdef MOAB_HAVE_VSNPRINTF
    // try once with remaining space in buffer
    lineBuffer.resize( lineBuffer.capacity() );
    unsigned size = vsnprintf( &lineBuffer[idx], lineBuffer.size() - idx, fmt, args1 );
    ++size;  // trailing null
    // if necessary, increase buffer size and retry
    if( size > ( lineBuffer.size() - idx ) )
    {
        lineBuffer.resize( idx + size );
        size = vsnprintf( &lineBuffer[idx], lineBuffer.size() - idx, fmt, args2 );
        ++size;  // trailing null
    }
#else
    // Guess how much space might be required.
    // If every character is a format code then there are len/3 format codes.
    // Guess a random large value of num_chars characters per formatted argument.
    const unsigned num_chars = 180;
    unsigned exp_size        = ( num_chars / 3 ) * strlen( fmt );
    lineBuffer.resize( idx + exp_size );
    unsigned size = vsprintf( &lineBuffer[idx], fmt, args1 );
    ++size;  // trailing null
    // check if we overflowed the buffer
    if( size > exp_size )
    {
        // crap!
        fprintf( stderr, "ERROR: Buffer overflow at %s:%d\n", __FILE__, __LINE__ );
        lineBuffer.resize( idx + exp_size );
        size = vsprintf( &lineBuffer[idx], fmt, args2 );
        ++size;  // trailing null
    }
#endif

    // less one because we don't want the trailing '\0'
    lineBuffer.resize( idx + size - 1 );
    process_line_buffer();
}

void ErrorOutput::process_line_buffer()
{
    size_t last_idx = 0;
    std::vector< char >::iterator i;
    for( i = std::find( lineBuffer.begin(), lineBuffer.end(), '\n' ); i != lineBuffer.end();
         i = std::find( i, lineBuffer.end(), '\n' ) )
    {
        *i = '\0';
        if( have_rank() )
            outputImpl->println( get_rank(), &lineBuffer[last_idx] );
        else
            outputImpl->println( &lineBuffer[last_idx] );
        ++i;
        last_idx = i - lineBuffer.begin();
    }

    if( last_idx )
    {
        i = std::copy( lineBuffer.begin() + last_idx, lineBuffer.end(), lineBuffer.begin() );
        lineBuffer.erase( i, lineBuffer.end() );
    }
}

}  // namespace moab