PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/liblangtag/lt-error.c

https://bitbucket.org/tagoh/liblangtag
C | 245 lines | 140 code | 25 blank | 80 comment | 32 complexity | 3953030e17df314b71870f5bb52fe6a5 MD5 | raw file
Possible License(s): LGPL-3.0, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
  2. /*
  3. * lt-error.c
  4. * Copyright (C) 2011-2012 Akira TAGOH
  5. *
  6. * Authors:
  7. * Akira TAGOH <akira@tagoh.org>
  8. *
  9. * You may distribute under the terms of either the GNU
  10. * Lesser General Public License or the Mozilla Public
  11. * License, as specified in the README file.
  12. */
  13. #ifdef HAVE_CONFIG_H
  14. #include "config.h"
  15. #endif
  16. #ifdef HAVE_EXECINFO_H
  17. #include <execinfo.h>
  18. #endif
  19. #include <stdlib.h>
  20. #include "lt-list.h"
  21. #include "lt-mem.h"
  22. #include "lt-messages.h"
  23. #include "lt-utils.h"
  24. #include "lt-error.h"
  25. struct _lt_error_t {
  26. lt_mem_t parent;
  27. lt_list_t *data;
  28. };
  29. typedef struct _lt_error_data_t {
  30. lt_mem_t parent;
  31. lt_error_type_t type;
  32. char *message;
  33. char **traces;
  34. size_t stack_size;
  35. } lt_error_data_t;
  36. /**
  37. * SECTION:lt-error
  38. * @Short_Description: Error handling
  39. * @Title: Error
  40. *
  41. * This section describes the error handling in this library.
  42. */
  43. /*< private >*/
  44. /**
  45. * lt_error_new:
  46. *
  47. * Creates #lt_error_t object. this function is protected and not supposed
  48. * to use in applications directly. Use lt_error_set().
  49. *
  50. * Returns: (transfer full): a newly allocated #lt_error_t. it has to be freed
  51. * with lt_error_unref().
  52. */
  53. lt_error_t *
  54. lt_error_new(void)
  55. {
  56. return lt_mem_alloc_object(sizeof (lt_error_t));
  57. }
  58. /*< public >*/
  59. /**
  60. * lt_error_ref:
  61. * @error: a #lt_error_t
  62. *
  63. * Inscreases the reference count of @error.
  64. *
  65. * Returns: (transfer none): the same @error object.
  66. */
  67. lt_error_t *
  68. lt_error_ref(lt_error_t *error)
  69. {
  70. lt_return_val_if_fail (error != NULL, NULL);
  71. return lt_mem_ref(&error->parent);
  72. }
  73. /**
  74. * lt_error_unref:
  75. * @error: a #lt_error_t
  76. *
  77. * Decreases the reference count of @error. when its reference count
  78. * drops to 0, the object is finalized (i.e. its memory is freed).
  79. */
  80. void
  81. lt_error_unref(lt_error_t *error)
  82. {
  83. if (error)
  84. lt_mem_unref(&error->parent);
  85. }
  86. /**
  87. * lt_error_set:
  88. * @error: a return location for a #lt_error_t
  89. * @type: a #lt_error_type_t
  90. * @message: the string format to output the error messages
  91. * @...: the parameters to insert into the format string
  92. *
  93. * Sets the error into @error according to the given parameters.
  94. *
  95. * Returns: an instance of #lt_error_t
  96. */
  97. lt_error_t *
  98. lt_error_set(lt_error_t **error,
  99. lt_error_type_t type,
  100. const char *message,
  101. ...)
  102. {
  103. va_list ap;
  104. #if HAVE_BACKTRACE
  105. void *traces[1024];
  106. #endif
  107. lt_error_data_t *d;
  108. int size = 0;
  109. lt_bool_t allocated;
  110. lt_return_val_if_fail (error != NULL, NULL);
  111. d = lt_mem_alloc_object(sizeof (lt_error_data_t));
  112. if (!d)
  113. goto bail0;
  114. if (!*error)
  115. *error = lt_error_new();
  116. if (!*error) {
  117. lt_mem_unref(&d->parent);
  118. goto bail0;
  119. }
  120. d->type = type;
  121. va_start(ap, message);
  122. d->message = lt_strdup_vprintf(message, ap);
  123. va_end(ap);
  124. #if HAVE_BACKTRACE
  125. size = backtrace(traces, 1024);
  126. if (size > 0)
  127. d->traces = backtrace_symbols(traces, size);
  128. #else
  129. d->traces = NULL;
  130. #endif
  131. d->stack_size = size;
  132. lt_mem_add_ref(&d->parent, d->message, free);
  133. if (d->traces)
  134. lt_mem_add_ref(&d->parent, d->traces, free);
  135. allocated = (*error)->data == NULL;
  136. (*error)->data = lt_list_append((*error)->data, d, (lt_destroy_func_t)lt_mem_unref);
  137. if (allocated)
  138. lt_mem_add_ref(&(*error)->parent,
  139. (*error)->data,
  140. (lt_destroy_func_t)lt_list_free);
  141. return *error;
  142. bail0:
  143. lt_critical("Out of memory");
  144. return *error;
  145. }
  146. /**
  147. * lt_error_clear:
  148. * @error: a #lt_error_t
  149. *
  150. * Clean up all of the errors in @error.
  151. */
  152. void
  153. lt_error_clear(lt_error_t *error)
  154. {
  155. if (error) {
  156. if (error->data)
  157. lt_mem_delete_ref(&error->parent, error->data);
  158. error->data = NULL;
  159. }
  160. }
  161. /**
  162. * lt_error_is_set:
  163. * @error: a #lt_error_t
  164. * @type: a #lt_error_type_t
  165. *
  166. * Checks if @error contains @type of errors. if #LT_ERR_ANY is set to @type,
  167. * all the types of the errors are targeted. otherwise the result is filtered
  168. * out by @type.
  169. *
  170. * Returns: %TRUE if any, otherwise %FALSE
  171. */
  172. lt_bool_t
  173. lt_error_is_set(lt_error_t *error,
  174. lt_error_type_t type)
  175. {
  176. if (type == LT_ERR_ANY) {
  177. return error && error->data;
  178. } else {
  179. if (error && error->data) {
  180. lt_list_t *l;
  181. for (l = error->data; l != NULL; l = lt_list_next(l)) {
  182. lt_error_data_t *d = lt_list_value(l);
  183. if (d->type == type)
  184. return TRUE;
  185. }
  186. }
  187. }
  188. return FALSE;
  189. }
  190. /**
  191. * lt_error_print:
  192. * @error: a #lt_error_t
  193. * @type: a #lt_error_type_t
  194. *
  195. * Output the error messages in @error according to @type.
  196. */
  197. void
  198. lt_error_print(lt_error_t *error,
  199. lt_error_type_t type)
  200. {
  201. lt_list_t *l;
  202. if (lt_error_is_set(error, type)) {
  203. lt_warning("Error raised:");
  204. for (l = error->data; l != NULL; l = lt_list_next(l)) {
  205. lt_error_data_t *d = lt_list_value(l);
  206. int i;
  207. if (type == LT_ERR_ANY || type == d->type) {
  208. lt_warning(" %s", d->message);
  209. if (d->stack_size > 0) {
  210. lt_warning(" Backtraces:");
  211. } else {
  212. lt_warning(" No backtraces");
  213. }
  214. for (i = 1; i < d->stack_size; i++) {
  215. lt_warning(" %d. %s", i - 1, d->traces[i]);
  216. }
  217. }
  218. }
  219. }
  220. }