1 // Copyright David Abrahams 2001.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef BOOST_PYTHON_SOURCE
7 # define BOOST_PYTHON_SOURCE
8 #endif
9 
10 #include <boost/python/errors.hpp>
11 #include <boost/cast.hpp>
12 #include <boost/python/detail/exception_handler.hpp>
13 
14 namespace boost { namespace python {
15 
~error_already_set()16 error_already_set::~error_already_set() {}
17 
18 // IMPORTANT: this function may only be called from within a catch block!
handle_exception_impl(function0<void> f)19 BOOST_PYTHON_DECL bool handle_exception_impl(function0<void> f)
20 {
21     try
22     {
23         if (detail::exception_handler::chain)
24             return detail::exception_handler::chain->handle(f);
25         f();
26         return false;
27     }
28     catch(const boost::python::error_already_set&)
29     {
30         // The python error reporting has already been handled.
31     }
32     catch(const std::bad_alloc&)
33     {
34         PyErr_NoMemory();
35     }
36     catch(const bad_numeric_cast& x)
37     {
38         PyErr_SetString(PyExc_OverflowError, x.what());
39     }
40     catch(const std::out_of_range& x)
41     {
42         PyErr_SetString(PyExc_IndexError, x.what());
43     }
44     catch(const std::invalid_argument& x)
45     {
46         PyErr_SetString(PyExc_ValueError, x.what());
47     }
48     catch(const std::exception& x)
49     {
50         PyErr_SetString(PyExc_RuntimeError, x.what());
51     }
52     catch(...)
53     {
54         PyErr_SetString(PyExc_RuntimeError, "unidentifiable C++ exception");
55     }
56     return true;
57 }
58 
throw_error_already_set()59 void BOOST_PYTHON_DECL throw_error_already_set()
60 {
61     throw error_already_set();
62 }
63 
64 namespace detail {
65 
operator ()(function0<void> const & f) const66 bool exception_handler::operator()(function0<void> const& f) const
67 {
68     if (m_next)
69     {
70         return m_next->handle(f);
71     }
72     else
73     {
74         f();
75         return false;
76     }
77 }
78 
exception_handler(handler_function const & impl)79 exception_handler::exception_handler(handler_function const& impl)
80     : m_impl(impl)
81     , m_next(0)
82 {
83     if (chain != 0)
84         tail->m_next = this;
85     else
86         chain = this;
87     tail = this;
88 }
89 
90 exception_handler* exception_handler::chain;
91 exception_handler* exception_handler::tail;
92 
register_exception_handler(handler_function const & f)93 BOOST_PYTHON_DECL void register_exception_handler(handler_function const& f)
94 {
95     // the constructor links the new object into a handler chain, so
96     // this object isn't actaully leaked (until, of course, the
97     // interpreter exits).
98     new exception_handler(f);
99 }
100 
101 } // namespace boost::python::detail
102 
103 }} // namespace boost::python
104 
105 
106