summaryrefslogtreecommitdiff
path: root/subversion/bindings/cxxhl/src/exception.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/bindings/cxxhl/src/exception.cpp')
-rw-r--r--subversion/bindings/cxxhl/src/exception.cpp339
1 files changed, 174 insertions, 165 deletions
diff --git a/subversion/bindings/cxxhl/src/exception.cpp b/subversion/bindings/cxxhl/src/exception.cpp
index 6c55792..0f0ee3f 100644
--- a/subversion/bindings/cxxhl/src/exception.cpp
+++ b/subversion/bindings/cxxhl/src/exception.cpp
@@ -28,6 +28,8 @@
#include <sstream>
#include "svncxxhl/exception.hpp"
+#include "private.hpp"
+#include "aprwrap.hpp"
#include "svn_error.h"
#include "svn_utf.h"
@@ -37,103 +39,85 @@
#undef TRUE
#undef FALSE
+namespace apache {
namespace subversion {
namespace cxxhl {
namespace detail {
-class error_description
+class ErrorDescription
{
public:
- static error_description* create(const char* message,
- const char *loc_file, long loc_line,
- bool trace_link)
+ typedef compat::shared_ptr<ErrorDescription> shared_ptr;
+
+ static shared_ptr create(const char* message, int error_code,
+ const char *loc_file, long loc_line,
+ bool trace_link)
{
- bool empty_message = (message == NULL);
+ const bool empty_message = (message == NULL);
const std::size_t length = (empty_message ? 0 : std::strlen(message));
- void *memblock = ::operator new(length + sizeof(error_description));
+ void* memblock = ::operator new(length + sizeof(ErrorDescription));
- error_description* description = new(memblock) error_description(
- loc_file, loc_line, trace_link, empty_message);
+ ErrorDescription* description = new(memblock) ErrorDescription(
+ error_code, loc_file, loc_line, trace_link, empty_message);
if (length)
std::memcpy(description->m_message, message, length);
description->m_message[length] = 0;
- return description;
+ return shared_ptr(description);
}
- static error_description* create(const char* message)
+ static shared_ptr create(const char* message, int error_code)
{
- return create(message, NULL, 0, false);
+ return create(message, error_code, NULL, 0, false);
}
- error_description* reference() throw()
- {
- if (this)
- svn_atomic_inc(&m_refcount);
- return this;
- }
-
- error_description* dereference() throw()
- {
- if (this && 0 == svn_atomic_dec(&m_refcount))
- {
- this->~error_description();
- ::operator delete(this, std::nothrow);
- return NULL;
- }
- return this;
- }
+ ~ErrorDescription() throw() {}
const char* what() const throw() { return (m_empty ? NULL : m_message); }
+ int code() const throw() { return m_errno; }
const char* file() const throw() { return m_loc_file; }
long line() const throw() { return m_loc_line; }
bool trace() const throw() { return m_trace; }
+ shared_ptr& nested() throw() { return m_nested; }
+ const shared_ptr& nested() const throw() { return m_nested; }
private:
- error_description(const char *loc_file, long loc_line,
- bool trace_link, bool empty_message) throw()
+ ErrorDescription(int error_code,
+ const char *loc_file, long loc_line,
+ bool trace_link, bool empty_message) throw()
: m_loc_file(loc_file),
m_loc_line(loc_line),
m_trace(trace_link),
m_empty(empty_message),
- m_refcount(0)
+ m_errno(error_code)
{}
- ~error_description() throw() {}
-
const char* m_loc_file;
long m_loc_line;
bool m_trace;
bool m_empty;
- volatile svn_atomic_t m_refcount;
- char m_message[1];
+ shared_ptr m_nested;
+
+ int m_errno; ///< The (SVN or APR) error code.
+ char m_message[1]; ///< The error message
};
} // namespace detail
+//
+// Class InternalError
+//
-namespace version_1_9_dev {
-
-error::error(const char* description, int error_code)
- : m_errno(error_code),
- m_description(detail::error_description::create(description)->reference())
-{}
-
-error::error(const char* description, int error_code,
- error::shared_ptr nested_error)
- : m_errno(error_code),
- m_nested(nested_error),
- m_description(detail::error_description::create(description)->reference())
+InternalError::InternalError(const char* description)
+ : m_description(detail::ErrorDescription::create(description, 0))
{}
-error::error(const error& that) throw()
- : m_errno(that.m_errno),
- m_nested(that.m_nested),
- m_description(that.m_description->reference())
+InternalError::InternalError(const InternalError& that) throw()
+ : m_description(that.m_description)
{}
-error& error::operator=(const error& that) throw()
+InternalError& InternalError::operator=(const InternalError& that) throw()
{
if (this == &that)
return *this;
@@ -141,89 +125,85 @@ error& error::operator=(const error& that) throw()
// This in-place destroy+copy implementation of the assignment
// operator is safe because both the destructor and the copy
// constructor do not throw exceptions.
- this->~error();
- return *new(this) error(that);
+ this->~InternalError();
+ return *new(this) InternalError(that);
}
-error::~error() throw()
-{
- m_description->dereference();
-}
+InternalError::~InternalError() throw() {}
-const char* error::what() const throw()
+const char* InternalError::what() const throw()
{
return m_description->what();
}
-error::error(int error_code, detail::error_description* description) throw()
- : m_errno(error_code),
- m_description(description)
+InternalError::InternalError(description_ptr description) throw()
+ : m_description(description)
{}
-void error::throw_svn_error(svn_error_t* err)
+//
+// Class Error
+//
+
+Error::Error(const Error& that) throw()
+ : InternalError(that.m_description)
+{}
+
+Error& Error::operator=(const Error& that) throw()
{
- const bool throw_cancelled = (err->apr_err == SVN_ERR_CANCELLED);
- detail::error_description* description = NULL;
- try
- {
- // Be very careful when creating the error descriptions, so that
- // the exception unwinder can free them if an allocation fails.
- // The private constructor does not increment the refcount
- // precisely for this reason.
+ if (this == &that)
+ return *this;
- shared_ptr nested;
- shared_ptr* current = &nested;
+ // This in-place destroy+copy implementation of the assignment
+ // operator is safe because both the destructor and the copy
+ // constructor do not throw exceptions.
+ this->~Error();
+ return *new(this) Error(that);
+}
- for (svn_error_t* next = err->child; next; next = next->child)
- {
- description = detail::error_description::create(
- next->message, next->file, next->line,
- svn_error__is_tracing_link(next));
- description->reference();
- current->reset(new error(next->apr_err, description));
- description = NULL;
- current = &(*current)->m_nested;
- }
+Error::~Error() throw() {}
- const int apr_err = err->apr_err;
- description = detail::error_description::create(
- err->message, err->file, err->line,
- svn_error__is_tracing_link(err));
- description->reference();
- svn_error_clear(err);
- if (throw_cancelled)
- {
- cancelled converted = cancelled(apr_err, description);
- description = NULL;
- converted.m_nested = nested;
- throw converted;
- }
- else
- {
- error converted = error(apr_err, description);
- description = NULL;
- converted.m_nested = nested;
- throw converted;
- }
- }
- catch (...)
+int Error::code() const throw()
+{
+ return m_description->code();
+}
+
+namespace {
+const char* get_generic_message(apr_status_t error_code,
+ const APR::Pool& scratch_pool)
+{
+ char errorbuf[512];
+
+ // Is this a Subversion-specific error code?
+ if (error_code > APR_OS_START_USEERR && error_code <= APR_OS_START_CANONERR)
+ return svn_strerror(error_code, errorbuf, sizeof(errorbuf));
+ // Otherwise, this must be an APR error code.
+ else
{
- description->dereference();
- throw;
+ const char* generic;
+ svn_error_t* err = svn_utf_cstring_to_utf8(
+ &generic,
+ apr_strerror(error_code, errorbuf, sizeof(errorbuf)),
+ scratch_pool.get());
+ if (!err)
+ return generic;
+
+ // Use fuzzy transliteration instead.
+ svn_error_clear(err);
+ return svn_utf_cstring_from_utf8_fuzzy(errorbuf, scratch_pool.get());
}
}
-
-namespace {
-void handle_one_error(error::message_list& ml, bool show_traces,
- int error_code, detail::error_description* descr,
- apr_pool_t* pool)
+void handle_one_error(Error::MessageList& ml, bool show_traces,
+ const detail::ErrorDescription* descr,
+ const APR::Pool& pool)
{
+ const int error_code = descr->code();
+
if (show_traces && descr->file())
{
const char* file_utf8 = NULL;
svn_error_t* err =
- svn_utf_cstring_to_utf8(&file_utf8, descr->file(), pool);
+ svn_utf_cstring_to_utf8(&file_utf8, descr->file(), pool.get());
if (err)
{
svn_error_clear(err);
@@ -234,8 +214,18 @@ void handle_one_error(error::message_list& ml, bool show_traces,
buffer << file_utf8 << ':' << descr->line();
else
buffer << "svn:<undefined>";
- buffer << ": (apr_err=" << error_code << ')';
- ml.push_back(error::message(0, buffer.str()));
+ if (descr->trace())
+ buffer << ',';
+ else
+ {
+#ifdef SVN_DEBUG
+ if (const char* symbolic_name = svn_error_symbolic_name(error_code))
+ buffer << ": (apr_err=" << symbolic_name << ')';
+ else
+#endif
+ buffer << ": (apr_err=" << error_code << ')';
+ }
+ ml.push_back(Error::Message(error_code, buffer.str(), true));
}
if (descr->trace())
@@ -243,43 +233,24 @@ void handle_one_error(error::message_list& ml, bool show_traces,
const char *description = descr->what();
if (!description)
- {
- char errorbuf[512];
-
- // Is this a Subversion-specific error code?
- if (error_code > APR_OS_START_USEERR
- && error_code <= APR_OS_START_CANONERR)
- description = svn_strerror(error_code, errorbuf, sizeof(errorbuf));
- // Otherwise, this must be an APR error code.
- else
- {
- svn_error_t* err = svn_utf_cstring_to_utf8(
- &description,
- apr_strerror(error_code, errorbuf, sizeof(errorbuf)),
- pool);
- if (err)
- {
- svn_error_clear(err);
- description = _("Can't recode error string from APR");
- }
- }
- }
- ml.push_back(error::message(error_code, std::string(description)));
+ description = get_generic_message(error_code, pool);
+ ml.push_back(Error::Message(error_code, std::string(description), false));
}
} // anonymous namespace
-error::message_list error::compile_messages(bool show_traces) const
+Error::MessageList Error::compile_messages(bool show_traces) const
{
// Determine the maximum size of the returned list
- message_list::size_type max_length = 0;
- for (const error* err = this; err; err = err->m_nested.get())
+ MessageList::size_type max_length = 0;
+ for (const detail::ErrorDescription* description = m_description.get();
+ description; description = description->nested().get())
{
- if (show_traces && m_description->file())
+ if (show_traces && description->file())
++max_length; // We will display an error location
- if (!m_description->trace())
+ if (!description->trace())
++max_length; // Traces do not emit a message line
}
- message_list ml;
+ MessageList ml;
ml.reserve(max_length);
// This vector holds a list of all error codes that we've printed
@@ -287,36 +258,74 @@ error::message_list error::compile_messages(bool show_traces) const
std::vector<int> empties;
empties.reserve(max_length);
- apr_pool_t* pool = NULL;
- apr_pool_create(&pool, NULL);
- try
+ APR::IterationPool iterbase;
+ for (const detail::ErrorDescription* description = m_description.get();
+ description; description = description->nested().get())
{
- for (const error* err = this; err; err = err->m_nested.get())
+ APR::Pool::Iteration iterpool(iterbase);
+
+ if (!description->what())
{
- if (!err->m_description->what())
- {
- // Non-specific messages are printed only once.
- std::vector<int>::iterator it = std::find(
- empties.begin(), empties.end(), err->m_errno);
- if (it != empties.end())
- continue;
- empties.push_back(err->m_errno);
- }
- handle_one_error(ml, show_traces,
- err->m_errno, err->m_description,
- pool);
+ // Non-specific messages are printed only once.
+ std::vector<int>::iterator it = std::find(
+ empties.begin(), empties.end(), description->code());
+ if (it != empties.end())
+ continue;
+ empties.push_back(description->code());
}
+ handle_one_error(ml, show_traces, description, iterpool.pool());
}
- catch (...)
+ return ml;
+}
+
+const char* Error::Message::generic_message() const
+{
+ APR::Pool pool;
+ return get_generic_message(m_errno, pool);
+}
+
+namespace detail {
+void checked_call(svn_error_t* err)
+{
+ if (!err)
+ return;
+
+ struct ErrorBuilder : public Error
+ {
+ explicit ErrorBuilder (ErrorDescription::shared_ptr description)
+ : Error(description)
+ {}
+ };
+
+ struct CancelledBuilder : public Cancelled
+ {
+ explicit CancelledBuilder (ErrorDescription::shared_ptr description)
+ : Cancelled(description)
+ {}
+ };
+
+ ErrorDescription::shared_ptr description;
+ ErrorDescription::shared_ptr* current = &description;
+
+ bool cancelled = false;
+ for (svn_error_t* next = err; next; next = next->child)
{
- apr_pool_destroy(pool);
- throw;
+ *current = ErrorDescription::create(next->message, next->apr_err,
+ next->file, next->line,
+ svn_error__is_tracing_link(next));
+ current = &(*current)->nested();
+ if (next->apr_err == SVN_ERR_CANCELLED)
+ cancelled = true;
}
+ svn_error_clear(err);
- apr_pool_destroy(pool);
- return ml;
+ if (cancelled)
+ throw CancelledBuilder(description);
+ else
+ throw ErrorBuilder(description);
}
+} // namespace detail
-} // namespace version_1_9_dev
} // namespace cxxhl
} // namespace subversion
+} // namespace apache