/*
* ====================================================================
* Copyright (c) 2002-2005 The RapidSvn Group. All rights reserved.
*
* This software is licensed as described in the file LICENSE.txt,
* which you should have received as part of this distribution.
*
* This software consists of voluntary contributions made by many
* individuals. For exact contribution history, see the revision
* history and logs, available at http://rapidsvn.tigris.org/.
* ====================================================================
*/
// stl
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <algorithm>
// subcpp
#include "exception.hpp"
// svn
#include "svn_wc.h"
namespace svn
{
struct Exception::Data
{
public:
std::string message;
apr_status_t apr_err;
Data( const char * msg )
: message( msg )
{
}
Data( const Data& other )
: message( other.message ), apr_err( other.apr_err )
{
}
};
Exception::Exception( const char * message ) throw()
{
m = new Data( message );
}
Exception::Exception( const Exception & other ) throw()
{
m = new Data( *other.m );
}
Exception::~Exception() throw()
{
delete m;
}
apr_status_t Exception::apr_err() const
{
return m->apr_err;
}
const char * Exception::Message() const
{
return m->message.c_str();
}
const char* Exception::what() const throw()
{
try
{
return Message();
}
catch( ... )
{
return "Encountered a new exception while creating this exception's message.";
}
}
ClientException::ClientException( svn_error_t * error ) throw()
: Exception( "" )
{
if ( error == 0 )
return;
Update( error );
svn_error_clear( error );
}
ClientException::ClientException( apr_status_t status ) throw()
: Exception( "" )
{
m->apr_err = status;
}
ClientException::~ClientException() throw()
{
}
ClientException::ClientException( const ClientException & src ) throw()
: Exception( src.Message() )
{
}
void ClientException::Update( svn_error_t * error )
{
if ( error == 0 )
return;
static const apr_size_t errMessageBufferSize = 500;
std::vector< char > errMessageOutBuffer( errMessageBufferSize, '\0' ); // 300 character error message seems enough?
m->apr_err = error->apr_err;
svn_error_t * next = error->child;
std::string & message = m->message;
std::vector< std::string > messages;
messages.push_back( svn_err_best_message( error, &errMessageOutBuffer[0], errMessageBufferSize ) );
while ( next != 0 )
{
messages.push_back( svn_err_best_message( next, &errMessageOutBuffer[0], errMessageBufferSize ) );
next = next->child;
}
// erase duplicates
messages.erase( std::unique( messages.begin(), messages.end() ), messages.end() );
// combine messagse
std::ostringstream combinedMessage;
std::copy( messages.begin(), messages.end(), std::ostream_iterator< std::string >( combinedMessage, "\n" ) );
// save combination
message = combinedMessage.str();
}
NotifyException::NotifyException() throw() : ClientException( 0 )
{
}
NotifyException::~NotifyException() throw()
{
}
NotifyException::NotifyException( const NotifyException& other ) : ClientException( other )
{
std::vector< const svn_wc_notify_t* >::const_iterator end = other.m_notifications.end();
for ( std::vector< const svn_wc_notify_t* >::const_iterator notification = other.m_notifications.begin(); notification != end; ++notification )
{
AddNotification( *notification );
}
};
void NotifyException::AddNotification( const svn_wc_notify_t* notification )
{
if( m_notifications.empty() )
{
Update( notification->err );
}
m_notifications.push_back( svn_wc_dup_notify( notification, m_pool.pool() ) );
}
ErrorChecker& operator << ( ErrorChecker& checker, svn_error_t* error )
{
if( NULL != error )
{
throw ClientException( error );
}
return( checker );
}
}