/src/glib-2.80.0/glib/gerror.c
Line | Count | Source |
1 | | /* GLIB - Library of useful routines for C programming |
2 | | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | | * |
4 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | /* |
21 | | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
22 | | * file for a list of people on the GLib Team. See the ChangeLog |
23 | | * files for a list of changes. These files are distributed with |
24 | | * GLib at ftp://ftp.gtk.org/pub/gtk/. |
25 | | */ |
26 | | |
27 | | #include "config.h" |
28 | | |
29 | | #include "gvalgrind.h" |
30 | | #include <string.h> |
31 | | |
32 | | #include "gerror.h" |
33 | | |
34 | | #include "ghash.h" |
35 | | #include "glib-init.h" |
36 | | #include "gslice.h" |
37 | | #include "gstrfuncs.h" |
38 | | #include "gtestutils.h" |
39 | | #include "gthread.h" |
40 | | |
41 | | static GRWLock error_domain_global; |
42 | | /* error_domain_ht must be accessed with error_domain_global |
43 | | * locked. |
44 | | */ |
45 | | static GHashTable *error_domain_ht = NULL; |
46 | | |
47 | | void |
48 | | g_error_init (void) |
49 | 12 | { |
50 | 12 | error_domain_ht = g_hash_table_new (NULL, NULL); |
51 | 12 | } |
52 | | |
53 | | typedef struct |
54 | | { |
55 | | /* private_size is already aligned. */ |
56 | | gsize private_size; |
57 | | GErrorInitFunc init; |
58 | | GErrorCopyFunc copy; |
59 | | GErrorClearFunc clear; |
60 | | } ErrorDomainInfo; |
61 | | |
62 | | /* Must be called with error_domain_global locked. |
63 | | */ |
64 | | static inline ErrorDomainInfo * |
65 | | error_domain_lookup (GQuark domain) |
66 | 25.8k | { |
67 | 25.8k | return g_hash_table_lookup (error_domain_ht, |
68 | 25.8k | GUINT_TO_POINTER (domain)); |
69 | 25.8k | } |
70 | | |
71 | | /* Copied from gtype.c. */ |
72 | 0 | #define STRUCT_ALIGNMENT (2 * sizeof (gsize)) |
73 | | #define ALIGN_STRUCT(offset) \ |
74 | 0 | ((offset + (STRUCT_ALIGNMENT - 1)) & -STRUCT_ALIGNMENT) |
75 | | |
76 | | static void |
77 | | error_domain_register (GQuark error_quark, |
78 | | gsize error_type_private_size, |
79 | | GErrorInitFunc error_type_init, |
80 | | GErrorCopyFunc error_type_copy, |
81 | | GErrorClearFunc error_type_clear) |
82 | 0 | { |
83 | 0 | g_rw_lock_writer_lock (&error_domain_global); |
84 | 0 | if (error_domain_lookup (error_quark) == NULL) |
85 | 0 | { |
86 | 0 | ErrorDomainInfo *info = g_new (ErrorDomainInfo, 1); |
87 | 0 | info->private_size = ALIGN_STRUCT (error_type_private_size); |
88 | 0 | info->init = error_type_init; |
89 | 0 | info->copy = error_type_copy; |
90 | 0 | info->clear = error_type_clear; |
91 | |
|
92 | 0 | g_hash_table_insert (error_domain_ht, |
93 | 0 | GUINT_TO_POINTER (error_quark), |
94 | 0 | info); |
95 | 0 | } |
96 | 0 | else |
97 | 0 | { |
98 | 0 | const char *name = g_quark_to_string (error_quark); |
99 | |
|
100 | 0 | g_critical ("Attempted to register an extended error domain for %s more than once", name); |
101 | 0 | } |
102 | 0 | g_rw_lock_writer_unlock (&error_domain_global); |
103 | 0 | } |
104 | | |
105 | | /** |
106 | | * g_error_domain_register_static: |
107 | | * @error_type_name: static string to create a #GQuark from |
108 | | * @error_type_private_size: size of the private error data in bytes |
109 | | * @error_type_init: (scope forever): function initializing fields of the private error data |
110 | | * @error_type_copy: (scope forever): function copying fields of the private error data |
111 | | * @error_type_clear: (scope forever): function freeing fields of the private error data |
112 | | * |
113 | | * This function registers an extended #GError domain. |
114 | | * |
115 | | * @error_type_name should not be freed. @error_type_private_size must |
116 | | * be greater than 0. |
117 | | * |
118 | | * @error_type_init receives an initialized #GError and should then initialize |
119 | | * the private data. |
120 | | * |
121 | | * @error_type_copy is a function that receives both original and a copy |
122 | | * #GError and should copy the fields of the private error data. The standard |
123 | | * #GError fields are already handled. |
124 | | * |
125 | | * @error_type_clear receives the pointer to the error, and it should free the |
126 | | * fields of the private error data. It should not free the struct itself though. |
127 | | * |
128 | | * Normally, it is better to use G_DEFINE_EXTENDED_ERROR(), as it |
129 | | * already takes care of passing valid information to this function. |
130 | | * |
131 | | * Returns: #GQuark representing the error domain |
132 | | * Since: 2.68 |
133 | | */ |
134 | | GQuark |
135 | | g_error_domain_register_static (const char *error_type_name, |
136 | | gsize error_type_private_size, |
137 | | GErrorInitFunc error_type_init, |
138 | | GErrorCopyFunc error_type_copy, |
139 | | GErrorClearFunc error_type_clear) |
140 | 0 | { |
141 | 0 | GQuark error_quark; |
142 | |
|
143 | 0 | g_return_val_if_fail (error_type_name != NULL, 0); |
144 | 0 | g_return_val_if_fail (error_type_private_size > 0, 0); |
145 | 0 | g_return_val_if_fail (error_type_init != NULL, 0); |
146 | 0 | g_return_val_if_fail (error_type_copy != NULL, 0); |
147 | 0 | g_return_val_if_fail (error_type_clear != NULL, 0); |
148 | | |
149 | 0 | error_quark = g_quark_from_static_string (error_type_name); |
150 | 0 | error_domain_register (error_quark, |
151 | 0 | error_type_private_size, |
152 | 0 | error_type_init, |
153 | 0 | error_type_copy, |
154 | 0 | error_type_clear); |
155 | 0 | return error_quark; |
156 | 0 | } |
157 | | |
158 | | /** |
159 | | * g_error_domain_register: |
160 | | * @error_type_name: string to create a #GQuark from |
161 | | * @error_type_private_size: size of the private error data in bytes |
162 | | * @error_type_init: (scope forever): function initializing fields of the private error data |
163 | | * @error_type_copy: (scope forever): function copying fields of the private error data |
164 | | * @error_type_clear: (scope forever): function freeing fields of the private error data |
165 | | * |
166 | | * This function registers an extended #GError domain. |
167 | | * @error_type_name will be duplicated. Otherwise does the same as |
168 | | * g_error_domain_register_static(). |
169 | | * |
170 | | * Returns: #GQuark representing the error domain |
171 | | * Since: 2.68 |
172 | | */ |
173 | | GQuark |
174 | | g_error_domain_register (const char *error_type_name, |
175 | | gsize error_type_private_size, |
176 | | GErrorInitFunc error_type_init, |
177 | | GErrorCopyFunc error_type_copy, |
178 | | GErrorClearFunc error_type_clear) |
179 | 0 | { |
180 | 0 | GQuark error_quark; |
181 | |
|
182 | 0 | g_return_val_if_fail (error_type_name != NULL, 0); |
183 | 0 | g_return_val_if_fail (error_type_private_size > 0, 0); |
184 | 0 | g_return_val_if_fail (error_type_init != NULL, 0); |
185 | 0 | g_return_val_if_fail (error_type_copy != NULL, 0); |
186 | 0 | g_return_val_if_fail (error_type_clear != NULL, 0); |
187 | | |
188 | 0 | error_quark = g_quark_from_string (error_type_name); |
189 | 0 | error_domain_register (error_quark, |
190 | 0 | error_type_private_size, |
191 | 0 | error_type_init, |
192 | 0 | error_type_copy, |
193 | 0 | error_type_clear); |
194 | 0 | return error_quark; |
195 | 0 | } |
196 | | |
197 | | static GError * |
198 | | g_error_allocate (GQuark domain, ErrorDomainInfo *out_info) |
199 | 12.9k | { |
200 | 12.9k | guint8 *allocated; |
201 | 12.9k | GError *error; |
202 | 12.9k | ErrorDomainInfo *info; |
203 | 12.9k | gsize private_size; |
204 | | |
205 | 12.9k | g_rw_lock_reader_lock (&error_domain_global); |
206 | 12.9k | info = error_domain_lookup (domain); |
207 | 12.9k | if (info != NULL) |
208 | 0 | { |
209 | 0 | if (out_info != NULL) |
210 | 0 | *out_info = *info; |
211 | 0 | private_size = info->private_size; |
212 | 0 | g_rw_lock_reader_unlock (&error_domain_global); |
213 | 0 | } |
214 | 12.9k | else |
215 | 12.9k | { |
216 | 12.9k | g_rw_lock_reader_unlock (&error_domain_global); |
217 | 12.9k | if (out_info != NULL) |
218 | 12.9k | memset (out_info, 0, sizeof (*out_info)); |
219 | 12.9k | private_size = 0; |
220 | 12.9k | } |
221 | | /* See comments in g_type_create_instance in gtype.c to see what |
222 | | * this magic is about. |
223 | | */ |
224 | 12.9k | #ifdef ENABLE_VALGRIND |
225 | 12.9k | if (private_size > 0 && RUNNING_ON_VALGRIND) |
226 | 0 | { |
227 | 0 | private_size += ALIGN_STRUCT (1); |
228 | 0 | allocated = g_slice_alloc0 (private_size + sizeof (GError) + sizeof (gpointer)); |
229 | 0 | *(gpointer *) (allocated + private_size + sizeof (GError)) = allocated + ALIGN_STRUCT (1); |
230 | 0 | VALGRIND_MALLOCLIKE_BLOCK (allocated + private_size, sizeof (GError) + sizeof (gpointer), 0, TRUE); |
231 | 0 | VALGRIND_MALLOCLIKE_BLOCK (allocated + ALIGN_STRUCT (1), private_size - ALIGN_STRUCT (1), 0, TRUE); |
232 | 0 | } |
233 | 12.9k | else |
234 | 12.9k | #endif |
235 | 12.9k | allocated = g_slice_alloc0 (private_size + sizeof (GError)); |
236 | | |
237 | 12.9k | error = (GError *) (allocated + private_size); |
238 | 12.9k | return error; |
239 | 12.9k | } |
240 | | |
241 | | /* This function takes ownership of @message. */ |
242 | | static GError * |
243 | | g_error_new_steal (GQuark domain, |
244 | | gint code, |
245 | | gchar *message, |
246 | | ErrorDomainInfo *out_info) |
247 | 12.9k | { |
248 | 12.9k | ErrorDomainInfo info; |
249 | 12.9k | GError *error = g_error_allocate (domain, &info); |
250 | | |
251 | 12.9k | error->domain = domain; |
252 | 12.9k | error->code = code; |
253 | 12.9k | error->message = message; |
254 | | |
255 | 12.9k | if (info.init != NULL) |
256 | 0 | info.init (error); |
257 | 12.9k | if (out_info != NULL) |
258 | 0 | *out_info = info; |
259 | | |
260 | 12.9k | return error; |
261 | 12.9k | } |
262 | | |
263 | | /** |
264 | | * g_error_new_valist: |
265 | | * @domain: error domain |
266 | | * @code: error code |
267 | | * @format: printf()-style format for error message |
268 | | * @args: #va_list of parameters for the message format |
269 | | * |
270 | | * Creates a new #GError with the given @domain and @code, |
271 | | * and a message formatted with @format. |
272 | | * |
273 | | * Returns: a new #GError |
274 | | * |
275 | | * Since: 2.22 |
276 | | */ |
277 | | GError* |
278 | | g_error_new_valist (GQuark domain, |
279 | | gint code, |
280 | | const gchar *format, |
281 | | va_list args) |
282 | 12.9k | { |
283 | 12.9k | g_return_val_if_fail (format != NULL, NULL); |
284 | | |
285 | | /* Historically, GError allowed this (although it was never meant to work), |
286 | | * and it has significant use in the wild, which g_return_val_if_fail |
287 | | * would break. It should maybe g_return_val_if_fail in GLib 4. |
288 | | * (GNOME#660371, GNOME#560482) |
289 | | */ |
290 | 12.9k | g_warn_if_fail (domain != 0); |
291 | | |
292 | 12.9k | return g_error_new_steal (domain, code, g_strdup_vprintf (format, args), NULL); |
293 | 12.9k | } |
294 | | |
295 | | /** |
296 | | * g_error_new: |
297 | | * @domain: error domain |
298 | | * @code: error code |
299 | | * @format: printf()-style format for error message |
300 | | * @...: parameters for message format |
301 | | * |
302 | | * Creates a new #GError with the given @domain and @code, |
303 | | * and a message formatted with @format. |
304 | | * |
305 | | * Returns: a new #GError |
306 | | */ |
307 | | GError* |
308 | | g_error_new (GQuark domain, |
309 | | gint code, |
310 | | const gchar *format, |
311 | | ...) |
312 | 0 | { |
313 | 0 | GError* error; |
314 | 0 | va_list args; |
315 | |
|
316 | 0 | g_return_val_if_fail (format != NULL, NULL); |
317 | 0 | g_return_val_if_fail (domain != 0, NULL); |
318 | | |
319 | 0 | va_start (args, format); |
320 | 0 | error = g_error_new_valist (domain, code, format, args); |
321 | 0 | va_end (args); |
322 | |
|
323 | 0 | return error; |
324 | 0 | } |
325 | | |
326 | | /** |
327 | | * g_error_new_literal: |
328 | | * @domain: error domain |
329 | | * @code: error code |
330 | | * @message: error message |
331 | | * |
332 | | * Creates a new #GError; unlike g_error_new(), @message is |
333 | | * not a printf()-style format string. Use this function if |
334 | | * @message contains text you don't have control over, |
335 | | * that could include printf() escape sequences. |
336 | | * |
337 | | * Returns: a new #GError |
338 | | **/ |
339 | | GError* |
340 | | g_error_new_literal (GQuark domain, |
341 | | gint code, |
342 | | const gchar *message) |
343 | 0 | { |
344 | 0 | g_return_val_if_fail (message != NULL, NULL); |
345 | 0 | g_return_val_if_fail (domain != 0, NULL); |
346 | | |
347 | 0 | return g_error_new_steal (domain, code, g_strdup (message), NULL); |
348 | 0 | } |
349 | | |
350 | | /** |
351 | | * g_error_free: |
352 | | * @error: a #GError |
353 | | * |
354 | | * Frees a #GError and associated resources. |
355 | | */ |
356 | | void |
357 | | g_error_free (GError *error) |
358 | 12.9k | { |
359 | 12.9k | gsize private_size; |
360 | 12.9k | ErrorDomainInfo *info; |
361 | 12.9k | guint8 *allocated; |
362 | | |
363 | 12.9k | g_return_if_fail (error != NULL); |
364 | | |
365 | 12.9k | g_rw_lock_reader_lock (&error_domain_global); |
366 | 12.9k | info = error_domain_lookup (error->domain); |
367 | 12.9k | if (info != NULL) |
368 | 0 | { |
369 | 0 | GErrorClearFunc clear = info->clear; |
370 | |
|
371 | 0 | private_size = info->private_size; |
372 | 0 | g_rw_lock_reader_unlock (&error_domain_global); |
373 | 0 | clear (error); |
374 | 0 | } |
375 | 12.9k | else |
376 | 12.9k | { |
377 | 12.9k | g_rw_lock_reader_unlock (&error_domain_global); |
378 | 12.9k | private_size = 0; |
379 | 12.9k | } |
380 | | |
381 | 12.9k | g_free (error->message); |
382 | 12.9k | allocated = ((guint8 *) error) - private_size; |
383 | | /* See comments in g_type_free_instance in gtype.c to see what this |
384 | | * magic is about. |
385 | | */ |
386 | 12.9k | #ifdef ENABLE_VALGRIND |
387 | 12.9k | if (private_size > 0 && RUNNING_ON_VALGRIND) |
388 | 0 | { |
389 | 0 | private_size += ALIGN_STRUCT (1); |
390 | 0 | allocated -= ALIGN_STRUCT (1); |
391 | 0 | *(gpointer *) (allocated + private_size + sizeof (GError)) = NULL; |
392 | 0 | g_slice_free1 (private_size + sizeof (GError) + sizeof (gpointer), allocated); |
393 | 0 | VALGRIND_FREELIKE_BLOCK (allocated + ALIGN_STRUCT (1), 0); |
394 | 0 | VALGRIND_FREELIKE_BLOCK (error, 0); |
395 | 0 | } |
396 | 12.9k | else |
397 | 12.9k | #endif |
398 | 12.9k | g_slice_free1 (private_size + sizeof (GError), allocated); |
399 | 12.9k | } |
400 | | |
401 | | /** |
402 | | * g_error_copy: |
403 | | * @error: a #GError |
404 | | * |
405 | | * Makes a copy of @error. |
406 | | * |
407 | | * Returns: a new #GError |
408 | | */ |
409 | | GError* |
410 | | g_error_copy (const GError *error) |
411 | 0 | { |
412 | 0 | GError *copy; |
413 | 0 | ErrorDomainInfo info; |
414 | |
|
415 | 0 | g_return_val_if_fail (error != NULL, NULL); |
416 | 0 | g_return_val_if_fail (error->message != NULL, NULL); |
417 | | |
418 | | /* See g_error_new_valist for why this doesn’t return */ |
419 | 0 | g_warn_if_fail (error->domain != 0); |
420 | |
|
421 | 0 | copy = g_error_new_steal (error->domain, |
422 | 0 | error->code, |
423 | 0 | g_strdup (error->message), |
424 | 0 | &info); |
425 | 0 | if (info.copy != NULL) |
426 | 0 | info.copy (error, copy); |
427 | |
|
428 | 0 | return copy; |
429 | 0 | } |
430 | | |
431 | | /** |
432 | | * g_error_matches: |
433 | | * @error: (nullable): a #GError |
434 | | * @domain: an error domain |
435 | | * @code: an error code |
436 | | * |
437 | | * Returns %TRUE if @error matches @domain and @code, %FALSE |
438 | | * otherwise. In particular, when @error is %NULL, %FALSE will |
439 | | * be returned. |
440 | | * |
441 | | * If @domain contains a `FAILED` (or otherwise generic) error code, |
442 | | * you should generally not check for it explicitly, but should |
443 | | * instead treat any not-explicitly-recognized error code as being |
444 | | * equivalent to the `FAILED` code. This way, if the domain is |
445 | | * extended in the future to provide a more specific error code for |
446 | | * a certain case, your code will still work. |
447 | | * |
448 | | * Returns: whether @error has @domain and @code |
449 | | */ |
450 | | gboolean |
451 | | g_error_matches (const GError *error, |
452 | | GQuark domain, |
453 | | gint code) |
454 | 0 | { |
455 | 0 | return error && |
456 | 0 | error->domain == domain && |
457 | 0 | error->code == code; |
458 | 0 | } |
459 | | |
460 | | #define ERROR_OVERWRITTEN_WARNING "GError set over the top of a previous GError or uninitialized memory.\n" \ |
461 | | "This indicates a bug in someone's code. You must ensure an error is NULL before it's set.\n" \ |
462 | | "The overwriting error message was: %s" |
463 | | |
464 | | /** |
465 | | * g_set_error: |
466 | | * @err: (out callee-allocates) (optional): a return location for a #GError |
467 | | * @domain: error domain |
468 | | * @code: error code |
469 | | * @format: printf()-style format |
470 | | * @...: args for @format |
471 | | * |
472 | | * Does nothing if @err is %NULL; if @err is non-%NULL, then *@err |
473 | | * must be %NULL. A new #GError is created and assigned to *@err. |
474 | | */ |
475 | | void |
476 | | g_set_error (GError **err, |
477 | | GQuark domain, |
478 | | gint code, |
479 | | const gchar *format, |
480 | | ...) |
481 | 12.9k | { |
482 | 12.9k | GError *new; |
483 | | |
484 | 12.9k | va_list args; |
485 | | |
486 | 12.9k | if (err == NULL) |
487 | 0 | return; |
488 | | |
489 | 12.9k | va_start (args, format); |
490 | 12.9k | new = g_error_new_valist (domain, code, format, args); |
491 | 12.9k | va_end (args); |
492 | | |
493 | 12.9k | if (*err == NULL) |
494 | 12.9k | *err = new; |
495 | 0 | else |
496 | 0 | { |
497 | 0 | g_warning (ERROR_OVERWRITTEN_WARNING, new->message); |
498 | 0 | g_error_free (new); |
499 | 0 | } |
500 | 12.9k | } |
501 | | |
502 | | /** |
503 | | * g_set_error_literal: |
504 | | * @err: (out callee-allocates) (optional): a return location for a #GError |
505 | | * @domain: error domain |
506 | | * @code: error code |
507 | | * @message: error message |
508 | | * |
509 | | * Does nothing if @err is %NULL; if @err is non-%NULL, then *@err |
510 | | * must be %NULL. A new #GError is created and assigned to *@err. |
511 | | * Unlike g_set_error(), @message is not a printf()-style format string. |
512 | | * Use this function if @message contains text you don't have control over, |
513 | | * that could include printf() escape sequences. |
514 | | * |
515 | | * Since: 2.18 |
516 | | */ |
517 | | void |
518 | | g_set_error_literal (GError **err, |
519 | | GQuark domain, |
520 | | gint code, |
521 | | const gchar *message) |
522 | 7.02k | { |
523 | 7.02k | if (err == NULL) |
524 | 7.02k | return; |
525 | | |
526 | 0 | if (*err == NULL) |
527 | 0 | *err = g_error_new_literal (domain, code, message); |
528 | 0 | else |
529 | 0 | g_warning (ERROR_OVERWRITTEN_WARNING, message); |
530 | 0 | } |
531 | | |
532 | | /** |
533 | | * g_propagate_error: |
534 | | * @dest: (out callee-allocates) (optional) (nullable): error return location |
535 | | * @src: (transfer full): error to move into the return location |
536 | | * |
537 | | * If @dest is %NULL, free @src; otherwise, moves @src into *@dest. |
538 | | * The error variable @dest points to must be %NULL. |
539 | | * |
540 | | * @src must be non-%NULL. |
541 | | * |
542 | | * Note that @src is no longer valid after this call. If you want |
543 | | * to keep using the same GError*, you need to set it to %NULL |
544 | | * after calling this function on it. |
545 | | */ |
546 | | void |
547 | | g_propagate_error (GError **dest, |
548 | | GError *src) |
549 | 0 | { |
550 | 0 | g_return_if_fail (src != NULL); |
551 | | |
552 | 0 | if (dest == NULL) |
553 | 0 | { |
554 | 0 | g_error_free (src); |
555 | 0 | return; |
556 | 0 | } |
557 | 0 | else |
558 | 0 | { |
559 | 0 | if (*dest != NULL) |
560 | 0 | { |
561 | 0 | g_warning (ERROR_OVERWRITTEN_WARNING, src->message); |
562 | 0 | g_error_free (src); |
563 | 0 | } |
564 | 0 | else |
565 | 0 | *dest = src; |
566 | 0 | } |
567 | 0 | } |
568 | | |
569 | | /** |
570 | | * g_clear_error: |
571 | | * @err: a #GError return location |
572 | | * |
573 | | * If @err or *@err is %NULL, does nothing. Otherwise, |
574 | | * calls g_error_free() on *@err and sets *@err to %NULL. |
575 | | */ |
576 | | void |
577 | | g_clear_error (GError **err) |
578 | 0 | { |
579 | 0 | if (err && *err) |
580 | 0 | { |
581 | 0 | g_error_free (*err); |
582 | 0 | *err = NULL; |
583 | 0 | } |
584 | 0 | } |
585 | | |
586 | | G_GNUC_PRINTF(2, 0) |
587 | | static void |
588 | | g_error_add_prefix (gchar **string, |
589 | | const gchar *format, |
590 | | va_list ap) |
591 | 0 | { |
592 | 0 | gchar *oldstring; |
593 | 0 | gchar *prefix; |
594 | |
|
595 | 0 | prefix = g_strdup_vprintf (format, ap); |
596 | 0 | oldstring = *string; |
597 | 0 | *string = g_strconcat (prefix, oldstring, NULL); |
598 | 0 | g_free (oldstring); |
599 | 0 | g_free (prefix); |
600 | 0 | } |
601 | | |
602 | | /** |
603 | | * g_prefix_error: |
604 | | * @err: (inout) (optional) (nullable): a return location for a #GError |
605 | | * @format: printf()-style format string |
606 | | * @...: arguments to @format |
607 | | * |
608 | | * Formats a string according to @format and prefix it to an existing |
609 | | * error message. If @err is %NULL (ie: no error variable) then do |
610 | | * nothing. |
611 | | * |
612 | | * If *@err is %NULL (ie: an error variable is present but there is no |
613 | | * error condition) then also do nothing. |
614 | | * |
615 | | * Since: 2.16 |
616 | | */ |
617 | | void |
618 | | g_prefix_error (GError **err, |
619 | | const gchar *format, |
620 | | ...) |
621 | 0 | { |
622 | 0 | if (err && *err) |
623 | 0 | { |
624 | 0 | va_list ap; |
625 | |
|
626 | 0 | va_start (ap, format); |
627 | 0 | g_error_add_prefix (&(*err)->message, format, ap); |
628 | 0 | va_end (ap); |
629 | 0 | } |
630 | 0 | } |
631 | | |
632 | | /** |
633 | | * g_prefix_error_literal: |
634 | | * @err: (inout) (nullable) (optional): a return location for a #GError, or %NULL |
635 | | * @prefix: string to prefix @err with |
636 | | * |
637 | | * Prefixes @prefix to an existing error message. If @err or *@err is |
638 | | * %NULL (i.e.: no error variable) then do nothing. |
639 | | * |
640 | | * Since: 2.70 |
641 | | */ |
642 | | void |
643 | | g_prefix_error_literal (GError **err, |
644 | | const gchar *prefix) |
645 | 0 | { |
646 | 0 | if (err && *err) |
647 | 0 | { |
648 | 0 | gchar *oldstring; |
649 | |
|
650 | 0 | oldstring = (*err)->message; |
651 | 0 | (*err)->message = g_strconcat (prefix, oldstring, NULL); |
652 | 0 | g_free (oldstring); |
653 | 0 | } |
654 | 0 | } |
655 | | |
656 | | /** |
657 | | * g_propagate_prefixed_error: |
658 | | * @dest: error return location |
659 | | * @src: error to move into the return location |
660 | | * @format: printf()-style format string |
661 | | * @...: arguments to @format |
662 | | * |
663 | | * If @dest is %NULL, free @src; otherwise, moves @src into *@dest. |
664 | | * *@dest must be %NULL. After the move, add a prefix as with |
665 | | * g_prefix_error(). |
666 | | * |
667 | | * Since: 2.16 |
668 | | **/ |
669 | | void |
670 | | g_propagate_prefixed_error (GError **dest, |
671 | | GError *src, |
672 | | const gchar *format, |
673 | | ...) |
674 | 0 | { |
675 | 0 | g_propagate_error (dest, src); |
676 | |
|
677 | 0 | if (dest) |
678 | 0 | { |
679 | 0 | va_list ap; |
680 | |
|
681 | 0 | g_assert (*dest != NULL); |
682 | 0 | va_start (ap, format); |
683 | 0 | g_error_add_prefix (&(*dest)->message, format, ap); |
684 | | va_end (ap); |
685 | 0 | } |
686 | 0 | } |