Line data Source code
1 : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 : /*
3 : * lt-messages.c
4 : * Copyright (C) 2006-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 : * Borrowed from hieroglyph:
14 : * http://cgit.freedesktop.org/hieroglyph/tree/hieroglyph/hgmessages.c
15 : */
16 : #ifdef HAVE_CONFIG_H
17 : #include "config.h"
18 : #endif
19 :
20 : #ifndef _WIN32
21 : #include <execinfo.h>
22 : #endif
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include "lt-messages.h"
27 :
28 : static void _lt_message_default_handler(lt_message_type_t type,
29 : lt_message_flags_t flags,
30 : lt_message_category_t category,
31 : const char *message,
32 : lt_pointer_t user_data);
33 :
34 :
35 : static lt_message_func_t __lt_message_default_handler = _lt_message_default_handler;
36 : static lt_pointer_t __lt_message_default_handler_data = NULL;
37 : static lt_message_func_t __lt_message_handler[LT_MSG_END];
38 : static lt_pointer_t __lt_message_handler_data[LT_MSG_END];
39 :
40 : /*< private >*/
41 : static char *
42 0 : _lt_message_get_prefix(lt_message_type_t type,
43 : lt_message_category_t category)
44 : {
45 : static const char *type_string[LT_MSG_END + 1] = {
46 : NULL,
47 : "*** ",
48 : "E: ",
49 : "W: ",
50 : "I: ",
51 : "D: ",
52 : NULL
53 : };
54 : static const char *category_string[LT_MSGCAT_END + 1] = {
55 : NULL,
56 : " DEBUG",
57 : " TRACE",
58 : "MODULE",
59 : NULL
60 : };
61 : static const char unknown_type[] = "?: ";
62 : static const char unknown_cat[] = "???";
63 : static const char no_cat[] = "";
64 : const char *ts, *cs;
65 0 : char *retval = NULL, *catstring = NULL;
66 0 : size_t tlen = 0, clen = 0, len;
67 :
68 0 : type = LT_MIN (type, LT_MSG_END);
69 0 : category = LT_MIN (category, LT_MSGCAT_END);
70 0 : if (type_string[type]) {
71 0 : ts = type_string[type];
72 : } else {
73 0 : ts = unknown_type;
74 : }
75 0 : tlen = strlen(ts);
76 0 : if (category_string[category]) {
77 0 : cs = category_string[category];
78 0 : } else if (category == 0) {
79 0 : cs = no_cat;
80 : } else {
81 0 : cs = unknown_cat;
82 : }
83 0 : clen = strlen(cs);
84 0 : if (clen > 0) {
85 0 : catstring = malloc(sizeof (char) * (clen + 6));
86 : #ifdef _WIN32
87 : _snprintf(catstring, clen + 6, "[%s]: ", cs);
88 : #else
89 0 : snprintf(catstring, clen + 6, "[%s]: ", cs);
90 : #endif
91 0 : clen = strlen(catstring);
92 : }
93 0 : len = tlen + clen + 1;
94 0 : retval = malloc(sizeof (char) * len);
95 0 : if (retval) {
96 : #ifdef _WIN32
97 : _snprintf(retval, len, "%s%s ", ts, catstring ? catstring : "");
98 : #else
99 0 : snprintf(retval, len, "%s%s ", ts, catstring ? catstring : "");
100 : #endif
101 : }
102 0 : if (catstring)
103 0 : free(catstring);
104 :
105 0 : return retval;
106 : }
107 :
108 : static void
109 0 : _lt_message_stacktrace(void)
110 : {
111 : #ifndef _WIN32
112 : void *traces[1024];
113 : char **strings;
114 : int size, i;
115 :
116 0 : size = backtrace(traces, 1024);
117 0 : if (size > 0) {
118 0 : strings = backtrace_symbols(traces, size);
119 0 : lt_debug(LT_MSGCAT_TRACE, "Stacktrace:");
120 : /*
121 : * XXX:
122 : * 0.. here.
123 : * 1.. _lt_message_default_handler
124 : * 2.. lt_message_vprintf
125 : * 3.. lt_message_printf
126 : * 4.. lt_* macros
127 : */
128 0 : for (i = 4; i < size; i++) {
129 0 : lt_debug(LT_MSGCAT_TRACE, " %d. %s", i - 3, strings[i]);
130 : }
131 0 : free(strings);
132 : }
133 : #endif
134 0 : }
135 :
136 : static void
137 0 : _lt_message_default_handler(lt_message_type_t type,
138 : lt_message_flags_t flags,
139 : lt_message_category_t category,
140 : const char *message,
141 : lt_pointer_t user_data)
142 : {
143 0 : char *prefix = NULL;
144 :
145 0 : if (flags == 0 || (flags & LT_MSG_FLAG_NO_PREFIX) == 0)
146 0 : prefix = _lt_message_get_prefix(type, category);
147 0 : fprintf(stderr, "%s%s%s", prefix ? prefix : "", message, flags == 0 || (flags & LT_MSG_FLAG_NO_LINEFEED) == 0 ? "\n" : "");
148 0 : if (lt_message_is_enabled(LT_MSGCAT_TRACE) && category != LT_MSGCAT_TRACE)
149 0 : _lt_message_stacktrace();
150 0 : if (lt_message_is_enabled(LT_MSGCAT_DEBUG) &&
151 : type != LT_MSG_DEBUG)
152 0 : LT_BREAKPOINT();
153 :
154 0 : if (prefix)
155 0 : free(prefix);
156 0 : }
157 :
158 : /*< public >*/
159 :
160 : lt_message_func_t
161 0 : lt_message_set_default_handler(lt_message_func_t func,
162 : lt_pointer_t user_data)
163 : {
164 0 : lt_message_func_t retval = __lt_message_default_handler;
165 :
166 0 : __lt_message_default_handler = func;
167 0 : __lt_message_default_handler_data = user_data;
168 :
169 0 : return retval;
170 : }
171 :
172 : lt_message_func_t
173 0 : lt_message_set_handler(lt_message_type_t type,
174 : lt_message_func_t func,
175 : lt_pointer_t user_data)
176 : {
177 : lt_message_func_t retval;
178 :
179 0 : if (type >= LT_MSG_END) {
180 0 : fprintf(stderr, "[BUG] invalid message type: %d\n", type);
181 0 : return NULL;
182 : }
183 :
184 0 : retval = __lt_message_handler[type];
185 0 : __lt_message_handler[type] = func;
186 0 : __lt_message_handler_data[type] = user_data;
187 :
188 0 : return retval;
189 : }
190 :
191 : lt_bool_t
192 20 : lt_message_is_enabled(lt_message_category_t category)
193 : {
194 : static lt_bool_t cache = FALSE;
195 : static int mask = 0;
196 : const char *env;
197 :
198 20 : if (!cache) {
199 4 : env = getenv("LT_DEBUG");
200 4 : if (env)
201 0 : mask = atoi(env);
202 4 : cache = TRUE;
203 : }
204 :
205 20 : return ((1 << (category - 1)) & mask) != 0;
206 : }
207 :
208 : void
209 20 : lt_message_printf(lt_message_type_t type,
210 : lt_message_flags_t flags,
211 : lt_message_category_t category,
212 : const char *format,
213 : ...)
214 : {
215 : va_list args;
216 :
217 20 : va_start(args, format);
218 :
219 20 : lt_message_vprintf(type, flags, category, format, args);
220 :
221 20 : va_end(args);
222 20 : }
223 :
224 : void
225 20 : lt_message_vprintf(lt_message_type_t type,
226 : lt_message_flags_t flags,
227 : lt_message_category_t category,
228 : const char *format,
229 : va_list args)
230 : {
231 : char buffer[4096];
232 :
233 20 : if (type >= LT_MSG_END) {
234 0 : fprintf(stderr, "[BUG] Invalid message type: %d\n", type);
235 : return;
236 : }
237 20 : if (category >= LT_MSGCAT_END) {
238 0 : fprintf(stderr, "[BUG] Invalid category type: %d\n", category);
239 : return;
240 : }
241 20 : if (type == LT_MSG_DEBUG) {
242 20 : if (!lt_message_is_enabled(category))
243 : return;
244 : }
245 :
246 0 : vsnprintf(buffer, 4096, format, args);
247 0 : if (__lt_message_handler[type]) {
248 0 : __lt_message_handler[type](type, flags, category, buffer, __lt_message_handler_data[type]);
249 0 : } else if (__lt_message_default_handler) {
250 0 : __lt_message_default_handler(type, flags, category, buffer, __lt_message_default_handler_data);
251 : }
252 0 : if (type == LT_MSG_FATAL)
253 0 : abort();
254 : }
255 :
256 : void
257 0 : lt_return_if_fail_warning(const char *pretty_function,
258 : const char *expression)
259 : {
260 0 : lt_message_printf(LT_MSG_CRITICAL,
261 : LT_MSG_FLAG_NONE,
262 : 0,
263 : "%s: assertion `%s' failed",
264 : pretty_function,
265 : expression);
266 0 : }
|