EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / lib / eina_magic.c
1 /* EINA - EFL data type library
2  * Copyright (C) 2008 Cedric Bail
3  *
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.
8  *
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.
13  *
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/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #ifdef HAVE_EVIL
27 # include <Evil.h>
28 #endif
29
30 #include "eina_config.h"
31 #include "eina_private.h"
32 #include "eina_error.h"
33 #include "eina_log.h"
34
35 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
36 #include "eina_safety_checks.h"
37 #include "eina_magic.h"
38
39 /*============================================================================*
40 *                                  Local                                     *
41 *============================================================================*/
42
43 /**
44  * @cond LOCAL
45  */
46
47 typedef struct _Eina_Magic_String Eina_Magic_String;
48 struct _Eina_Magic_String
49 {
50    Eina_Magic magic;
51    Eina_Bool string_allocated;
52    const char *string;
53 };
54
55 static int _eina_magic_string_log_dom = -1;
56
57 #ifdef ERR
58 #undef ERR
59 #endif
60 #define ERR(...) EINA_LOG_DOM_ERR(_eina_magic_string_log_dom, __VA_ARGS__)
61
62 #ifdef DBG
63 #undef DBG
64 #endif
65 #define DBG(...) EINA_LOG_DOM_DBG(_eina_magic_string_log_dom, __VA_ARGS__)
66
67 static Eina_Magic_String *_eina_magic_strings = NULL;
68 static size_t _eina_magic_strings_count = 0;
69 static size_t _eina_magic_strings_allocated = 0;
70 static Eina_Bool _eina_magic_strings_dirty = 0;
71
72 static int
73 _eina_magic_strings_sort_cmp(const void *p1, const void *p2)
74 {
75    const Eina_Magic_String *a = p1, *b = p2;
76    return a->magic - b->magic;
77 }
78
79 static int
80 _eina_magic_strings_find_cmp(const void *p1, const void *p2)
81 {
82    Eina_Magic a = (Eina_Magic)(size_t)p1;
83    const Eina_Magic_String *b = p2;
84    return a - b->magic;
85 }
86
87 static Eina_Magic_String *
88 _eina_magic_strings_alloc(void)
89 {
90    size_t idx;
91
92    if (_eina_magic_strings_count == _eina_magic_strings_allocated)
93      {
94         void *tmp;
95         size_t size;
96
97         if (EINA_UNLIKELY(_eina_magic_strings_allocated == 0))
98            size = 48;
99         else
100            size = _eina_magic_strings_allocated + 16;
101
102         tmp = realloc(_eina_magic_strings, sizeof(Eina_Magic_String) * size);
103         if (!tmp)
104           {
105              ERR("could not realloc magic_strings from %zu to %zu buckets.",
106                  _eina_magic_strings_allocated, size);
107              return NULL;
108           }
109
110         _eina_magic_strings = tmp;
111         _eina_magic_strings_allocated = size;
112      }
113
114    idx = _eina_magic_strings_count;
115    _eina_magic_strings_count++;
116    return _eina_magic_strings + idx;
117 }
118
119 /**
120  * @endcond
121  */
122
123 /*============================================================================*
124 *                                 Global                                     *
125 *============================================================================*/
126
127 EAPI Eina_Error EINA_ERROR_MAGIC_FAILED = 0;
128
129 static const char EINA_ERROR_MAGIC_FAILED_STR[] = "Magic check failed.";
130
131 /**
132  * @internal
133  * @brief Initialize the magic string module.
134  *
135  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
136  *
137  * This function sets up the magic string module of Eina. It is called by
138  * eina_init().
139  *
140  * @see eina_init()
141  */
142 Eina_Bool
143 eina_magic_string_init(void)
144 {
145    _eina_magic_string_log_dom = eina_log_domain_register
146          ("eina_magic_string", EINA_LOG_COLOR_DEFAULT);
147    if (_eina_magic_string_log_dom < 0)
148      {
149         EINA_LOG_ERR("Could not register log domain: eina_magic_string");
150         return EINA_FALSE;
151      }
152    EINA_ERROR_MAGIC_FAILED = eina_error_msg_static_register(
153          EINA_ERROR_MAGIC_FAILED_STR);
154
155    return EINA_TRUE;
156 }
157
158 /**
159  * @internal
160  * @brief Shut down the magic string module.
161  *
162  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
163  *
164  * This function shuts down the magic string module set up by
165  * eina_magic string_init(). It is called by eina_shutdown().
166  *
167  * @see eina_shutdown()
168  */
169 Eina_Bool
170 eina_magic_string_shutdown(void)
171 {
172    Eina_Magic_String *ems, *ems_end;
173
174    ems = _eina_magic_strings;
175    ems_end = ems + _eina_magic_strings_count;
176
177    for (; ems < ems_end; ems++)
178       if (ems->string_allocated)
179          free((char *)ems->string);
180
181          free(_eina_magic_strings);
182    _eina_magic_strings = NULL;
183    _eina_magic_strings_count = 0;
184    _eina_magic_strings_allocated = 0;
185
186    eina_log_domain_unregister(_eina_magic_string_log_dom);
187    _eina_magic_string_log_dom = -1;
188
189    return EINA_TRUE;
190 }
191
192 /*============================================================================*
193 *                                   API                                      *
194 *============================================================================*/
195 EAPI const char *
196 eina_magic_string_get(Eina_Magic magic)
197 {
198    Eina_Magic_String *ems;
199
200    if (!_eina_magic_strings)
201       return "(none)";
202
203    if (_eina_magic_strings_dirty)
204      {
205         qsort(_eina_magic_strings, _eina_magic_strings_count,
206               sizeof(Eina_Magic_String), _eina_magic_strings_sort_cmp);
207         _eina_magic_strings_dirty = 0;
208      }
209
210    ems = bsearch((void *)(size_t)magic, _eina_magic_strings,
211                  _eina_magic_strings_count, sizeof(Eina_Magic_String),
212                  _eina_magic_strings_find_cmp);
213    if (ems)
214       return ems->string ? ems->string : "(undefined)";
215
216    return "(unknown)";
217 }
218
219 EAPI Eina_Bool
220 eina_magic_string_set(Eina_Magic magic, const char *magic_name)
221 {
222    Eina_Magic_String *ems;
223
224    EINA_SAFETY_ON_NULL_RETURN_VAL(magic_name, EINA_FALSE);
225
226    ems = _eina_magic_strings_alloc();
227    if (!ems)
228       return EINA_FALSE;
229
230    ems->magic = magic;
231    ems->string_allocated = EINA_TRUE;
232    ems->string = strdup(magic_name);
233    if (!ems->string)
234    {
235       ERR("could not allocate string '%s'", magic_name);
236       _eina_magic_strings_count--;
237       return EINA_FALSE;
238    }
239
240    _eina_magic_strings_dirty = 1;
241    return EINA_TRUE;
242 }
243
244 EAPI Eina_Bool
245 eina_magic_string_static_set(Eina_Magic magic, const char *magic_name)
246 {
247    Eina_Magic_String *ems;
248
249    EINA_SAFETY_ON_NULL_RETURN_VAL(magic_name, EINA_FALSE);
250
251    ems = _eina_magic_strings_alloc();
252    if (!ems)
253       return EINA_FALSE;
254
255    ems->magic = magic;
256    ems->string_allocated = EINA_FALSE;
257    ems->string = magic_name;
258
259    _eina_magic_strings_dirty = 1;
260    return EINA_TRUE;
261 }
262
263 #ifdef eina_magic_fail
264 # undef eina_magic_fail
265 #endif
266
267 EAPI void
268 eina_magic_fail(void *d,
269                 Eina_Magic m,
270                 Eina_Magic req_m,
271                 const char *file,
272                 const char *fnc,
273                 int line)
274 {
275    eina_error_set(EINA_ERROR_MAGIC_FAILED);
276    if (!d)
277       eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
278                      file, fnc, line,
279                      "*** Eina Magic Check Failed !!!\n"
280                      "    Input handle pointer is NULL !\n"
281                      "*** NAUGHTY PROGRAMMER!!!\n"
282                      "*** SPANK SPANK SPANK!!!\n"
283                      "*** Now go fix your code. Tut tut tut!\n"
284                      "\n");
285    else
286    if (m == EINA_MAGIC_NONE)
287       eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
288                      file, fnc, line,
289                      "*** Eina Magic Check Failed !!!\n"
290                      "    Input handle has already been freed!\n"
291                      "*** NAUGHTY PROGRAMMER!!!\n"
292                      "*** SPANK SPANK SPANK!!!\n"
293                      "*** Now go fix your code. Tut tut tut!\n"
294                      "\n");
295    else
296    if (m != req_m)
297       eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
298                      file, fnc, line,
299                      "*** Eina Magic Check Failed !!!\n"
300                      "    Input handle is wrong type\n"
301                      "    Expected: %08x - %s\n"
302                      "    Supplied: %08x - %s\n"
303                      "*** NAUGHTY PROGRAMMER!!!\n"
304                      "*** SPANK SPANK SPANK!!!\n"
305                      "*** Now go fix your code. Tut tut tut!\n"
306                      "\n",
307                      req_m, eina_magic_string_get(req_m),
308                      m, eina_magic_string_get(m));
309    else
310       eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
311                      file, fnc, line,
312                      "*** Eina Magic Check Failed !!!\n"
313                      "    Why did you call me !\n"
314                      "*** NAUGHTY PROGRAMMER!!!\n"
315                      "*** SPANK SPANK SPANK!!!\n"
316                      "*** Now go fix your code. Tut tut tut!\n"
317                      "\n");
318 }
319
320 /**
321  * @}
322  */