1 /* EINA - EFL data type library
2 * Copyright (C) 2008 Cedric Bail
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
30 #include "eina_config.h"
31 #include "eina_private.h"
32 #include "eina_error.h"
35 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
36 #include "eina_safety_checks.h"
37 #include "eina_magic.h"
39 /*============================================================================*
41 *============================================================================*/
47 typedef struct _Eina_Magic_String Eina_Magic_String;
48 struct _Eina_Magic_String
54 static int _eina_magic_string_log_dom = -1;
56 #define ERR(...) EINA_LOG_DOM_ERR(_eina_magic_string_log_dom, __VA_ARGS__)
57 #define DBG(...) EINA_LOG_DOM_DBG(_eina_magic_string_log_dom, __VA_ARGS__)
59 static Eina_Magic_String *_eina_magic_strings = NULL;
60 static size_t _eina_magic_strings_count = 0;
61 static size_t _eina_magic_strings_allocated = 0;
62 static Eina_Bool _eina_magic_strings_dirty = 0;
65 _eina_magic_strings_sort_cmp(const void *p1, const void *p2)
67 const Eina_Magic_String *a = p1, *b = p2;
68 return a->magic - b->magic;
72 _eina_magic_strings_find_cmp(const void *p1, const void *p2)
74 Eina_Magic a = (long)p1;
75 const Eina_Magic_String *b = p2;
83 /*============================================================================*
85 *============================================================================*/
87 /*============================================================================*
89 *============================================================================*/
92 * @addtogroup Eina_Magic_Group Magic
94 * @brief These functions provide magic checks management for projects.
101 * @brief Initialize the magic string module.
103 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
105 * This function sets up the magic string module of Eina. It is called by
111 eina_magic_string_init(void)
113 _eina_magic_string_log_dom = eina_log_domain_register
114 ("eina_magic_string", EINA_LOG_COLOR_DEFAULT);
115 if (_eina_magic_string_log_dom < 0)
117 EINA_LOG_ERR("Could not register log domain: eina_magic_string");
126 * @brief Shut down the magic string module.
128 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
130 * This function shuts down the magic string module set up by
131 * eina_magic string_init(). It is called by eina_shutdown().
133 * @see eina_shutdown()
136 eina_magic_string_shutdown(void)
140 for (i = 0; i < _eina_magic_strings_count; i++)
141 free(_eina_magic_strings[i].string);
143 free(_eina_magic_strings);
144 _eina_magic_strings = NULL;
145 _eina_magic_strings_count = 0;
146 _eina_magic_strings_allocated = 0;
148 eina_log_domain_unregister(_eina_magic_string_log_dom);
149 _eina_magic_string_log_dom = -1;
155 * @brief Return the string associated to the given magic identifier.
157 * @param magic The magic identifier.
158 * @return The string associated to the identifier.
160 * This function returns the string associated to @p magic. If none
161 * are found, the this function returns @c NULL. The returned value
165 eina_magic_string_get(Eina_Magic magic)
167 Eina_Magic_String *ems;
169 if (!_eina_magic_strings)
172 if (_eina_magic_strings_dirty)
174 qsort(_eina_magic_strings, _eina_magic_strings_count,
175 sizeof(Eina_Magic_String), _eina_magic_strings_sort_cmp);
176 _eina_magic_strings_dirty = 0;
179 ems = bsearch((void *)(long)magic, _eina_magic_strings,
180 _eina_magic_strings_count, sizeof(Eina_Magic_String),
181 _eina_magic_strings_find_cmp);
188 * @brief Set the string associated to the given magic identifier.
190 * @param magic The magic identifier.
191 * @param The string associated to the identifier, must not be @c NULL.
193 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
195 * This function sets the string @p magic_name to @p magic. It is not
196 * checked if number or string are already set, then you might end
197 * with duplicates in that case.
200 eina_magic_string_set(Eina_Magic magic, const char *magic_name)
202 Eina_Magic_String *ems;
204 EINA_SAFETY_ON_NULL_RETURN_VAL(magic_name, EINA_FALSE);
206 if (_eina_magic_strings_count == _eina_magic_strings_allocated)
211 if (EINA_UNLIKELY(_eina_magic_strings_allocated == 0))
214 size = _eina_magic_strings_allocated + 16;
216 tmp = realloc(_eina_magic_strings, sizeof(Eina_Magic_String) * size);
219 ERR("could not realloc magic_strings from %zu to %zu buckets.",
220 _eina_magic_strings_allocated, size);
223 _eina_magic_strings = tmp;
224 _eina_magic_strings_allocated = size;
227 ems = _eina_magic_strings + _eina_magic_strings_count;
229 ems->string = strdup(magic_name);
232 ERR("could not allocate string '%s'", magic_name);
236 _eina_magic_strings_count++;
237 _eina_magic_strings_dirty = 1;
241 #ifdef eina_magic_fail
242 # undef eina_magic_fail
246 * @brief Display a message or abort is a magic check failed.
248 * @param d The checked data pointer.
249 * @param m The magic identifer to check.
250 * @param req_m The requested magic identifier to check.
251 * @param file The file in which the magic check failed.
252 * @param fcn The function in which the magic check failed.
253 * @param line The line at which the magic check failed.
255 * This function displays an error message if a magic check has
256 * failed, using the following logic in the following order:
257 * @li If @p d is @c NULL, a message warns about a @c NULL pointer.
258 * @li Otherwise, if @p m is equal to #EINA_MAGIC_NONE, a message
259 * warns about a handle that was already freed.
260 * @li Otherwise, if @p m is equal to @p req_m, a message warns about
261 * a handle that is of wrong type.
262 * @li Otherwise, a message warns you about ab-using that function...
264 * If the environment variable EINA_ERROR_ABORT is set, abort() is
265 * called and the program stops. It is useful for debugging programs
269 eina_magic_fail(void *d, Eina_Magic m, Eina_Magic req_m, const char *file, const char *fnc, int line)
272 eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
274 "*** Eina Magic Check Failed !!!\n"
275 " Input handle pointer is NULL !\n"
276 "*** NAUGHTY PROGRAMMER!!!\n"
277 "*** SPANK SPANK SPANK!!!\n"
278 "*** Now go fix your code. Tut tut tut!\n"
281 if (m == EINA_MAGIC_NONE)
282 eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
284 "*** Eina Magic Check Failed !!!\n"
285 " Input handle has already been freed!\n"
286 "*** NAUGHTY PROGRAMMER!!!\n"
287 "*** SPANK SPANK SPANK!!!\n"
288 "*** Now go fix your code. Tut tut tut!\n"
292 eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
294 "*** Eina Magic Check Failed !!!\n"
295 " Input handle is wrong type\n"
296 " Expected: %08x - %s\n"
297 " Supplied: %08x - %s\n"
298 "*** NAUGHTY PROGRAMMER!!!\n"
299 "*** SPANK SPANK SPANK!!!\n"
300 "*** Now go fix your code. Tut tut tut!\n"
302 req_m, eina_magic_string_get(req_m),
303 m, eina_magic_string_get(m));
305 eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
307 "*** Eina Magic Check Failed !!!\n"
308 " Why did you call me !\n"
309 "*** NAUGHTY PROGRAMMER!!!\n"
310 "*** SPANK SPANK SPANK!!!\n"
311 "*** Now go fix your code. Tut tut tut!\n"