PageRenderTime 79ms CodeModel.GetById 70ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/liblangtag/lt-error.c

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