PageRenderTime 4ms CodeModel.GetById 2ms app.highlight 10ms 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
  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;
117	int size = 0;
118	lt_bool_t allocated;
119
120	lt_return_val_if_fail (error != NULL, NULL);
121
122	d = lt_mem_alloc_object(sizeof (lt_error_data_t));
123	if (!d)
124		goto bail0;
125	if (!*error)
126		*error = lt_error_new();
127	if (!*error) {
128		lt_mem_unref(&d->parent);
129		goto bail0;
130	}
131
132	d->type = type;
133	va_start(ap, message);
134	d->message = lt_strdup_vprintf(message, ap);
135	va_end(ap);
136
137#if HAVE_BACKTRACE
138	size = backtrace(traces, 1024);
139	if (size > 0)
140		d->traces = backtrace_symbols(traces, size);
141#else
142	d->traces = NULL;
143#endif
144	d->stack_size = size;
145
146	lt_mem_add_ref(&d->parent, d->message, free);
147	if (d->traces)
148		lt_mem_add_ref(&d->parent, d->traces, free);
149
150	allocated = (*error)->data == NULL;
151	(*error)->data = lt_list_append((*error)->data, d, (lt_destroy_func_t)lt_mem_unref);
152	if (allocated)
153		lt_mem_add_ref(&(*error)->parent,
154			       (*error)->data,
155			       (lt_destroy_func_t)lt_list_free);
156
157	return *error;
158  bail0:
159	lt_critical("Out of memory");
160
161	return *error;
162}
163
164/**
165 * lt_error_clear:
166 * @error: a #lt_error_t
167 *
168 * Clean up all of the errors in @error.
169 */
170void
171lt_error_clear(lt_error_t *error)
172{
173	if (error) {
174		if (error->data)
175			lt_mem_delete_ref(&error->parent, error->data);
176		error->data = NULL;
177	}
178}
179
180/**
181 * lt_error_is_set:
182 * @error: a #lt_error_t
183 * @type: a #lt_error_type_t
184 *
185 * Checks if @error contains @type of errors. if #LT_ERR_ANY is set to @type,
186 * all the types of the errors are targeted. otherwise the result is filtered
187 * out by @type.
188 *
189 * Returns: %TRUE if any, otherwise %FALSE
190 */
191lt_bool_t
192lt_error_is_set(lt_error_t      *error,
193		lt_error_type_t  type)
194{
195	if (type == LT_ERR_ANY) {
196		return error && error->data;
197	} else {
198		if (error && error->data) {
199			lt_list_t *l;
200
201			for (l = error->data; l != NULL; l = lt_list_next(l)) {
202				lt_error_data_t *d = lt_list_value(l);
203
204				if (d->type == type)
205					return TRUE;
206			}
207		}
208	}
209
210	return FALSE;
211}
212
213/**
214 * lt_error_print:
215 * @error: a #lt_error_t
216 * @type: a #lt_error_type_t
217 *
218 * Output the error messages in @error according to @type.
219 */
220void
221lt_error_print(lt_error_t      *error,
222	       lt_error_type_t  type)
223{
224	lt_list_t *l;
225
226	if (lt_error_is_set(error, type)) {
227		lt_warning("Error raised:");
228		for (l = error->data; l != NULL; l = lt_list_next(l)) {
229			lt_error_data_t *d = lt_list_value(l);
230			int i;
231
232			if (type == LT_ERR_ANY || type == d->type) {
233				lt_warning("  %s", d->message);
234				if (d->stack_size > 0) {
235					lt_warning("  Backtraces:");
236				} else {
237					lt_warning("  No backtraces");
238				}
239				for (i = 1; i < d->stack_size; i++) {
240					lt_warning("    %d. %s", i - 1, d->traces[i]);
241				}
242			}
243		}
244	}
245}