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.cpp322
1 files changed, 322 insertions, 0 deletions
diff --git a/subversion/bindings/cxxhl/src/exception.cpp b/subversion/bindings/cxxhl/src/exception.cpp
new file mode 100644
index 0000000..6c55792
--- /dev/null
+++ b/subversion/bindings/cxxhl/src/exception.cpp
@@ -0,0 +1,322 @@
+/**
+ * @copyright
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <new>
+#include <sstream>
+
+#include "svncxxhl/exception.hpp"
+
+#include "svn_error.h"
+#include "svn_utf.h"
+#include "private/svn_atomic.h"
+#include "private/svn_error_private.h"
+#include "svn_private_config.h"
+#undef TRUE
+#undef FALSE
+
+namespace subversion {
+namespace cxxhl {
+
+namespace detail {
+
+class error_description
+{
+public:
+ static error_description* create(const char* message,
+ const char *loc_file, long loc_line,
+ bool trace_link)
+ {
+ bool empty_message = (message == NULL);
+ const std::size_t length = (empty_message ? 0 : std::strlen(message));
+ void *memblock = ::operator new(length + sizeof(error_description));
+
+ error_description* description = new(memblock) error_description(
+ loc_file, loc_line, trace_link, empty_message);
+ if (length)
+ std::memcpy(description->m_message, message, length);
+ description->m_message[length] = 0;
+ return description;
+ }
+
+ static error_description* create(const char* message)
+ {
+ return create(message, 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;
+ }
+
+ const char* what() const throw() { return (m_empty ? NULL : m_message); }
+ const char* file() const throw() { return m_loc_file; }
+ long line() const throw() { return m_loc_line; }
+ bool trace() const throw() { return m_trace; }
+
+private:
+ error_description(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)
+ {}
+
+ ~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];
+};
+
+} // namespace detail
+
+
+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())
+{}
+
+error::error(const error& that) throw()
+ : m_errno(that.m_errno),
+ m_nested(that.m_nested),
+ m_description(that.m_description->reference())
+{}
+
+error& error::operator=(const error& that) throw()
+{
+ if (this == &that)
+ return *this;
+
+ // 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);
+}
+
+error::~error() throw()
+{
+ m_description->dereference();
+}
+
+const char* error::what() const throw()
+{
+ return m_description->what();
+}
+
+error::error(int error_code, detail::error_description* description) throw()
+ : m_errno(error_code),
+ m_description(description)
+{}
+
+void error::throw_svn_error(svn_error_t* err)
+{
+ 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.
+
+ shared_ptr nested;
+ shared_ptr* current = &nested;
+
+ 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;
+ }
+
+ 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 (...)
+ {
+ description->dereference();
+ throw;
+ }
+}
+
+
+namespace {
+void handle_one_error(error::message_list& ml, bool show_traces,
+ int error_code, detail::error_description* descr,
+ apr_pool_t* pool)
+{
+ if (show_traces && descr->file())
+ {
+ const char* file_utf8 = NULL;
+ svn_error_t* err =
+ svn_utf_cstring_to_utf8(&file_utf8, descr->file(), pool);
+ if (err)
+ {
+ svn_error_clear(err);
+ file_utf8 = NULL;
+ }
+ std::ostringstream buffer;
+ if (file_utf8)
+ 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())
+ return;
+
+ 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)));
+}
+} // anonymous namespace
+
+error::message_list 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())
+ {
+ if (show_traces && m_description->file())
+ ++max_length; // We will display an error location
+ if (!m_description->trace())
+ ++max_length; // Traces do not emit a message line
+ }
+ message_list ml;
+ ml.reserve(max_length);
+
+ // This vector holds a list of all error codes that we've printed
+ // the generic description for. See svn_handle_error2 for details.
+ std::vector<int> empties;
+ empties.reserve(max_length);
+
+ apr_pool_t* pool = NULL;
+ apr_pool_create(&pool, NULL);
+ try
+ {
+ for (const error* err = this; err; err = err->m_nested.get())
+ {
+ 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);
+ }
+ }
+ catch (...)
+ {
+ apr_pool_destroy(pool);
+ throw;
+ }
+
+ apr_pool_destroy(pool);
+ return ml;
+}
+
+} // namespace version_1_9_dev
+} // namespace cxxhl
+} // namespace subversion