1 /* error.cc
2  *
3  * Copyright 2002 The gtkmm Development Team
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <glibmmconfig.h>
20 #include <glibmm/error.h>
21 #include <glibmm/wrap.h>
22 #include <glibmm/wrap_init.h>
23 #include <glib.h>
24 #include <map>
25 
26 namespace
27 {
28 
29 using ThrowFuncTable = std::map<GQuark, Glib::Error::ThrowFunc>;
30 
31 static ThrowFuncTable* throw_func_table = nullptr;
32 
33 } // anonymous namespace
34 
35 namespace Glib
36 {
37 
Error()38 Error::Error() : gobject_(nullptr)
39 {
40 }
41 
Error(GQuark error_domain,int error_code,const Glib::ustring & message)42 Error::Error(GQuark error_domain, int error_code, const Glib::ustring& message)
43 : gobject_(g_error_new_literal(error_domain, error_code, message.c_str()))
44 {
45 }
46 
Error(GError * gobject,bool take_copy)47 Error::Error(GError* gobject, bool take_copy)
48 : gobject_((take_copy && gobject) ? g_error_copy(gobject) : gobject)
49 {
50 }
51 
Error(const Error & other)52 Error::Error(const Error& other)
53 : Exception(other), gobject_((other.gobject_) ? g_error_copy(other.gobject_) : nullptr)
54 {
55 }
56 
57 Error&
operator =(const Error & other)58 Error::operator=(const Error& other)
59 {
60   if (gobject_ != other.gobject_)
61   {
62     if (gobject_)
63     {
64       g_error_free(gobject_);
65       gobject_ = nullptr;
66     }
67     if (other.gobject_)
68     {
69       gobject_ = g_error_copy(other.gobject_);
70     }
71   }
72   return *this;
73 }
74 
~Error()75 Error::~Error() noexcept
76 {
77   if (gobject_)
78     g_error_free(gobject_);
79 }
80 
operator bool() const81 Error::operator bool() const
82 {
83   return gobject_ != nullptr;
84 }
85 
86 GQuark
domain() const87 Error::domain() const
88 {
89   g_return_val_if_fail(gobject_ != nullptr, 0);
90 
91   return gobject_->domain;
92 }
93 
94 int
code() const95 Error::code() const
96 {
97   g_return_val_if_fail(gobject_ != nullptr, -1);
98 
99   return gobject_->code;
100 }
101 
102 Glib::ustring
what() const103 Error::what() const
104 {
105   g_return_val_if_fail(gobject_ != nullptr, "");
106   g_return_val_if_fail(gobject_->message != nullptr, "");
107 
108   return gobject_->message;
109 }
110 
111 bool
matches(GQuark error_domain,int error_code) const112 Error::matches(GQuark error_domain, int error_code) const
113 {
114   return g_error_matches(gobject_, error_domain, error_code);
115 }
116 
117 GError*
gobj()118 Error::gobj()
119 {
120   return gobject_;
121 }
122 
123 const GError*
gobj() const124 Error::gobj() const
125 {
126   return gobject_;
127 }
128 
129 void
propagate(GError ** dest)130 Error::propagate(GError** dest)
131 {
132   g_propagate_error(dest, gobject_);
133   gobject_ = nullptr;
134 }
135 
136 // static
137 void
register_init()138 Error::register_init()
139 {
140   if (!throw_func_table)
141   {
142     throw_func_table = new ThrowFuncTable();
143     Glib::wrap_register_init();
144     Glib::wrap_init(); // make sure that at least the Glib exceptions are registered
145   }
146 }
147 
148 // static
149 void
register_cleanup()150 Error::register_cleanup()
151 {
152   if (throw_func_table)
153   {
154     delete throw_func_table;
155     throw_func_table = nullptr;
156   }
157 }
158 
159 // static
160 void
register_domain(GQuark error_domain,Error::ThrowFunc throw_func)161 Error::register_domain(GQuark error_domain, Error::ThrowFunc throw_func)
162 {
163   g_assert(throw_func_table != nullptr);
164 
165   (*throw_func_table)[error_domain] = throw_func;
166 }
167 
168 // static, noreturn
169 void
throw_exception(GError * gobject)170 Error::throw_exception(GError* gobject)
171 {
172   g_assert(gobject != nullptr);
173 
174   // Just in case Gtk::Main hasn't been instantiated yet.
175   if (!throw_func_table)
176     register_init();
177 
178   if (const ThrowFunc throw_func = (*throw_func_table)[gobject->domain])
179   {
180     (*throw_func)(gobject);
181     g_assert_not_reached();
182   }
183 
184   g_warning("Glib::Error::throw_exception():\n  "
185             "unknown error domain '%s': throwing generic Glib::Error exception\n",
186     (gobject->domain) ? g_quark_to_string(gobject->domain) : "(null)");
187 
188   // Doesn't copy, because error-returning functions return a newly allocated GError for us.
189   throw Glib::Error(gobject);
190 }
191 
192 // Glib::Value<Glib::Error>
value_type()193 GType Value<Error>::value_type()
194 {
195   return g_error_get_type();
196 }
197 
set(const CppType & data)198 void Value<Error>::set(const CppType& data)
199 {
200   set_boxed(data.gobj());
201 }
202 
get() const203 Value<Error>::CppType Value<Error>::get() const
204 {
205   return Glib::Error(static_cast<CType>(get_boxed()), true);
206 }
207 
208 } // namespace Glib
209