eina: completly disable backtrace.
[framework/uifw/eina.git] / src / lib / eina_log.c
1 /* EINA - EFL data type library
2  * Copyright (C) 2007-2009 Jorge Luis Zapata Muga, Cedric Bail, Andre Dieb
3  * Martins
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library;
17  * if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <fnmatch.h>
28 #include <assert.h>
29 #include <errno.h>
30
31 #if 0
32 #if defined HAVE_EXECINFO_H && defined HAVE_BACKTRACE && defined HAVE_BACKTRACE_SYMBOLS
33 # include <execinfo.h>
34 # define EINA_LOG_BACKTRACE
35 #endif
36 #endif
37
38 #ifdef HAVE_UNISTD_H
39 # include <unistd.h>
40 #endif
41
42 #ifdef EFL_HAVE_POSIX_THREADS
43 # include <pthread.h>
44 #endif
45
46 #ifdef HAVE_EVIL
47 # include <Evil.h>
48 #endif
49
50 #include "eina_config.h"
51 #include "eina_private.h"
52 #include "eina_inlist.h"
53
54 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
55 #include "eina_safety_checks.h"
56 #include "eina_log.h"
57
58 /* TODO
59  * + printing logs to stdout or stderr can be implemented
60  * using a queue, useful for multiple threads printing
61  * + add a wrapper for assert?
62  */
63
64 /*============================================================================*
65 *                                  Local                                     *
66 *============================================================================*/
67
68 /**
69  * @cond LOCAL
70  */
71
72 #define EINA_LOG_ENV_ABORT "EINA_LOG_ABORT"
73 #define EINA_LOG_ENV_ABORT_LEVEL "EINA_LOG_ABORT_LEVEL"
74 #define EINA_LOG_ENV_LEVEL "EINA_LOG_LEVEL"
75 #define EINA_LOG_ENV_LEVELS "EINA_LOG_LEVELS"
76 #define EINA_LOG_ENV_LEVELS_GLOB "EINA_LOG_LEVELS_GLOB"
77 #define EINA_LOG_ENV_COLOR_DISABLE "EINA_LOG_COLOR_DISABLE"
78 #define EINA_LOG_ENV_FILE_DISABLE "EINA_LOG_FILE_DISABLE"
79 #define EINA_LOG_ENV_FUNCTION_DISABLE "EINA_LOG_FUNCTION_DISABLE"
80 #define EINA_LOG_ENV_BACKTRACE "EINA_LOG_BACKTRACE"
81
82 #ifdef EINA_ENABLE_LOG
83
84 // Structure for storing domain level settings passed from the command line
85 // that will be matched with application-defined domains.
86 typedef struct _Eina_Log_Domain_Level_Pending Eina_Log_Domain_Level_Pending;
87 struct _Eina_Log_Domain_Level_Pending
88 {
89    EINA_INLIST;
90    unsigned int level;
91    size_t namelen;
92    char name[];
93 };
94
95 /*
96  * List of levels for domains set by the user before the domains are registered,
97  * updates the domain levels on the first log and clears itself.
98  */
99 static Eina_Inlist *_pending_list = NULL;
100 static Eina_Inlist *_glob_list = NULL;
101
102 // Disable color flag (can be changed through the env var
103 // EINA_LOG_ENV_COLOR_DISABLE).
104 static Eina_Bool _disable_color = EINA_FALSE;
105 static Eina_Bool _disable_file = EINA_FALSE;
106 static Eina_Bool _disable_function = EINA_FALSE;
107 static Eina_Bool _abort_on_critical = EINA_FALSE;
108 static int _abort_level_on_critical = EINA_LOG_LEVEL_CRITICAL;
109
110 #ifdef EINA_LOG_BACKTRACE
111 static int _backtrace_level = -1;
112 #endif
113
114 #ifdef EFL_HAVE_THREADS
115
116 static Eina_Bool _threads_enabled = EINA_FALSE;
117 static Eina_Bool _threads_inited = EINA_FALSE;
118
119 # ifdef EFL_HAVE_POSIX_THREADS
120
121 typedef pthread_t Thread;
122
123 static pthread_t _main_thread;
124
125 #  define SELF() pthread_self()
126 #  define IS_MAIN(t)  pthread_equal(t, _main_thread)
127 #  define IS_OTHER(t) EINA_UNLIKELY(!IS_MAIN(t))
128 #  define CHECK_MAIN(...)                                         \
129    do {                                                           \
130       if (!IS_MAIN(pthread_self())) {                             \
131          fprintf(stderr,                                          \
132                  "ERR: not main thread! current=%lu, main=%lu\n", \
133                  (unsigned long)pthread_self(),                   \
134                  (unsigned long)_main_thread);                    \
135          return __VA_ARGS__;                                      \
136       }                                                           \
137    } while (0)
138
139 #  ifdef EFL_HAVE_POSIX_THREADS_SPINLOCK
140
141 static pthread_spinlock_t _log_lock;
142
143 static Eina_Bool _eina_log_spinlock_init(void)
144 {
145    if (pthread_spin_init(&_log_lock, PTHREAD_PROCESS_PRIVATE) == 0)
146      return EINA_TRUE;
147
148    fprintf(stderr,
149            "ERROR: pthread_spin_init(%p, PTHREAD_PROCESS_PRIVATE): %s\n",
150            &_log_lock, strerror(errno));
151    return EINA_FALSE;
152 }
153
154 #   define LOG_LOCK()                                                  \
155    if (_threads_enabled)                                               \
156          do {                                                          \
157             if (0) {                                                   \
158                fprintf(stderr, "+++LOG LOG_LOCKED!   [%s, %lu]\n",     \
159                        __FUNCTION__, (unsigned long)pthread_self()); } \
160             if (EINA_UNLIKELY(_threads_enabled)) {                     \
161                pthread_spin_lock(&_log_lock); }                        \
162          } while (0)
163 #   define LOG_UNLOCK()                                                \
164    if (_threads_enabled)                                               \
165          do {                                                          \
166             if (EINA_UNLIKELY(_threads_enabled)) {                     \
167                pthread_spin_unlock(&_log_lock); }                      \
168             if (0) {                                                   \
169                fprintf(stderr,                                         \
170                        "---LOG LOG_UNLOCKED! [%s, %lu]\n",             \
171                        __FUNCTION__, (unsigned long)pthread_self()); } \
172          } while (0)
173 #   define INIT() _eina_log_spinlock_init()
174 #   define SHUTDOWN() pthread_spin_destroy(&_log_lock)
175
176 #  else /* ! EFL_HAVE_POSIX_THREADS_SPINLOCK */
177
178 static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
179 #   define LOG_LOCK() if(_threads_enabled) {pthread_mutex_lock(&_log_mutex); }
180 #   define LOG_UNLOCK() if(_threads_enabled) {pthread_mutex_unlock(&_log_mutex); }
181 #   define INIT() (1)
182 #   define SHUTDOWN() do {} while (0)
183
184 #  endif /* ! EFL_HAVE_POSIX_THREADS_SPINLOCK */
185
186 # else /* EFL_HAVE_WIN32_THREADS */
187
188 typedef DWORD Thread;
189
190 static DWORD _main_thread;
191
192 #  define SELF() GetCurrentThreadId()
193 #  define IS_MAIN(t)  (t == _main_thread)
194 #  define IS_OTHER(t) EINA_UNLIKELY(!IS_MAIN(t))
195 #  define CHECK_MAIN(...)                                         \
196    do {                                                           \
197       if (!IS_MAIN(GetCurrentThreadId())) {                       \
198          fprintf(stderr,                                          \
199                  "ERR: not main thread! current=%lu, main=%lu\n", \
200                  GetCurrentThreadId(), _main_thread);             \
201          return __VA_ARGS__;                                      \
202       }                                                           \
203    } while (0)
204
205 static HANDLE _log_mutex = NULL;
206
207 #  define LOG_LOCK() if(_threads_enabled) WaitForSingleObject(_log_mutex, INFINITE)
208 #  define LOG_UNLOCK() if(_threads_enabled) ReleaseMutex(_log_mutex)
209 #  define INIT() ((_log_mutex = CreateMutex(NULL, FALSE, NULL)) ? 1 : 0)
210 #  define SHUTDOWN()  if (_log_mutex) CloseHandle(_log_mutex)
211
212 # endif /* EFL_HAVE_WIN32_THREADS */
213
214 #else /* ! EFL_HAVE_THREADS */
215
216 # define LOG_LOCK() do {} while (0)
217 # define LOG_UNLOCK() do {} while (0)
218 # define IS_MAIN(t)  (1)
219 # define IS_OTHER(t) (0)
220 # define CHECK_MAIN(...) do {} while (0)
221 # define INIT() (1)
222 # define SHUTDOWN() do {} while (0)
223
224 #endif /* ! EFL_HAVE_THREADS */
225
226
227 // List of domains registered
228 static Eina_Log_Domain *_log_domains = NULL;
229 static unsigned int _log_domains_count = 0;
230 static size_t _log_domains_allocated = 0;
231
232 // Default function for printing on domains
233 static Eina_Log_Print_Cb _print_cb = eina_log_print_cb_stderr;
234 static void *_print_cb_data = NULL;
235
236 #ifdef DEBUG
237 static Eina_Log_Level _log_level = EINA_LOG_LEVEL_DBG;
238 #elif DEBUG_CRITICAL
239 static Eina_Log_Level _log_level = EINA_LOG_LEVEL_CRITICAL;
240 #else
241 static Eina_Log_Level _log_level = EINA_LOG_LEVEL_ERR;
242 #endif
243
244 /* NOTE: if you change this, also change:
245  *   eina_log_print_level_name_get()
246  *   eina_log_print_level_name_color_get()
247  */
248 static const char *_names[] = {
249    "CRI",
250    "ERR",
251    "WRN",
252    "INF",
253    "DBG",
254 };
255
256 #ifdef _WIN32
257 static int
258 eina_log_win32_color_get(const char *domain_str)
259 {
260    char *str;
261    char *tmp;
262    char *tmp2;
263    int code = -1;
264    int lighted = 0;
265    int ret = 0;
266
267    str = strdup(domain_str);
268    if (!str)
269       return 0;
270
271    /* this should not append */
272    if (str[0] != '\033')
273      {
274         free(str);
275         return 0;
276      }
277
278    /* we skip the first char and the [ */
279    tmp = tmp2 = str + 2;
280    while (*tmp != 'm')
281      {
282         if (*tmp == ';')
283           {
284              *tmp = '\0';
285              code = atol(tmp2);
286              tmp++;
287              tmp2 = tmp;
288           }
289
290         tmp++;
291      }
292    *tmp = '\0';
293    if (code < 0)
294       code = atol(tmp2);
295    else
296       lighted = atol(tmp2);
297
298    free(str);
299
300    if (code < lighted)
301      {
302         int c;
303
304         c = code;
305         code = lighted;
306         lighted = c;
307      }
308
309    if (lighted)
310       ret = FOREGROUND_INTENSITY;
311
312    if (code == 31)
313       ret |= FOREGROUND_RED;
314    else if (code == 32)
315       ret |= FOREGROUND_GREEN;
316    else if (code == 33)
317       ret |= FOREGROUND_RED | FOREGROUND_GREEN;
318    else if (code == 34)
319       ret |= FOREGROUND_BLUE;
320    else if (code == 36)
321       ret |= FOREGROUND_GREEN | FOREGROUND_BLUE;
322    else if (code == 37)
323       ret |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
324
325    return ret;
326 }
327 #endif
328
329 static inline unsigned int
330 eina_log_pid_get(void)
331 {
332    return (unsigned int)getpid();
333 }
334
335 static inline void
336 eina_log_print_level_name_get(int level, const char **p_name)
337 {
338    static char buf[4];
339    /* NOTE: if you change this, also change
340     *    eina_log_print_level_name_color_get()
341     *    eina_log_level_name_get() (at eina_inline_log.x)
342     */
343    if (EINA_UNLIKELY(level < 0))
344      {
345         snprintf(buf, sizeof(buf), "%03d", level);
346         *p_name = buf;
347      }
348    else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
349      {
350         snprintf(buf, sizeof(buf), "%03d", level);
351         *p_name = buf;
352      }
353    else
354       *p_name = _names[level];
355 }
356
357 #ifdef _WIN32
358 static inline void
359 eina_log_print_level_name_color_get(int level,
360                                     const char **p_name,
361                                     int *p_color)
362 {
363    static char buf[4];
364    /* NOTE: if you change this, also change:
365     *   eina_log_print_level_name_get()
366     */
367    if (EINA_UNLIKELY(level < 0))
368      {
369         snprintf(buf, sizeof(buf), "%03d", level);
370         *p_name = buf;
371      }
372    else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
373      {
374         snprintf(buf, sizeof(buf), "%03d", level);
375         *p_name = buf;
376      }
377    else
378       *p_name = _names[level];
379
380    *p_color = eina_log_win32_color_get(eina_log_level_color_get(level));
381 }
382 #else
383 static inline void
384 eina_log_print_level_name_color_get(int level,
385                                     const char **p_name,
386                                     const char **p_color)
387 {
388    static char buf[4];
389    /* NOTE: if you change this, also change:
390     *   eina_log_print_level_name_get()
391     */
392    if (EINA_UNLIKELY(level < 0))
393      {
394         snprintf(buf, sizeof(buf), "%03d", level);
395         *p_name = buf;
396      }
397    else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
398      {
399         snprintf(buf, sizeof(buf), "%03d", level);
400         *p_name = buf;
401      }
402    else
403       *p_name = _names[level];
404
405    *p_color = eina_log_level_color_get(level);
406 }
407 #endif
408
409 #define DECLARE_LEVEL_NAME(level) const char *name; \
410    eina_log_print_level_name_get(level, &name)
411 #ifdef _WIN32
412 # define DECLARE_LEVEL_NAME_COLOR(level) const char *name; int color; \
413    eina_log_print_level_name_color_get(level, &name, &color)
414 #else
415 # define DECLARE_LEVEL_NAME_COLOR(level) const char *name, *color; \
416    eina_log_print_level_name_color_get(level, &name, &color)
417 #endif
418
419 /** No threads, No color */
420 static void
421 eina_log_print_prefix_NOthreads_NOcolor_file_func(FILE *fp,
422                                                   const Eina_Log_Domain *d,
423                                                   Eina_Log_Level level,
424                                                   const char *file,
425                                                   const char *fnc,
426                                                   int line)
427 {
428    DECLARE_LEVEL_NAME(level);
429    fprintf(fp, "%s<%u>:%s %s:%d %s() ", name, eina_log_pid_get(), 
430            d->domain_str, file, line, fnc);
431 }
432
433 static void
434 eina_log_print_prefix_NOthreads_NOcolor_NOfile_func(FILE *fp,
435                                                     const Eina_Log_Domain *d,
436                                                     Eina_Log_Level level,
437                                                     const char *file __UNUSED__,
438                                                     const char *fnc,
439                                                     int line __UNUSED__)
440 {
441    DECLARE_LEVEL_NAME(level);
442    fprintf(fp, "%s<%u>:%s %s() ", name, eina_log_pid_get(), d->domain_str, 
443            fnc);
444 }
445
446 static void
447 eina_log_print_prefix_NOthreads_NOcolor_file_NOfunc(FILE *fp,
448                                                     const Eina_Log_Domain *d,
449                                                     Eina_Log_Level level,
450                                                     const char *file,
451                                                     const char *fnc __UNUSED__,
452                                                     int line)
453 {
454    DECLARE_LEVEL_NAME(level);
455    fprintf(fp, "%s<%u>:%s %s:%d ", name, eina_log_pid_get(), d->domain_str, 
456            file, line);
457 }
458
459 /* No threads, color */
460 static void
461 eina_log_print_prefix_NOthreads_color_file_func(FILE *fp,
462                                                 const Eina_Log_Domain *d,
463                                                 Eina_Log_Level level,
464                                                 const char *file,
465                                                 const char *fnc,
466                                                 int line)
467 {
468    DECLARE_LEVEL_NAME_COLOR(level);
469 #ifdef _WIN32_WCE
470    fprintf(fp, "%s<%u>:%s %s:%d %s() ", name, eina_log_pid_get(), 
471            d->domain_str, file, line, fnc);
472 #elif _WIN32
473    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
474                            color);
475    fprintf(fp, "%s", name);
476    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
477                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
478    fprintf(fp, ":");
479    SetConsoleTextAttribute(GetStdHandle(
480                               STD_OUTPUT_HANDLE),
481                            eina_log_win32_color_get(d->domain_str));
482    fprintf(fp, "%s", d->name);
483    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
484                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
485    fprintf(fp, " %s:%d ", file, line);
486    SetConsoleTextAttribute(GetStdHandle(
487                               STD_OUTPUT_HANDLE),
488                            FOREGROUND_INTENSITY | FOREGROUND_RED |
489                            FOREGROUND_GREEN | FOREGROUND_BLUE);
490    fprintf(fp, "%s()", fnc);
491    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
492                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
493    fprintf(fp, " ");
494 #else
495    fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s %s:%d "
496            EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
497            color, name, eina_log_pid_get(), d->domain_str, file, line, fnc);
498 #endif
499 }
500
501 static void
502 eina_log_print_prefix_NOthreads_color_NOfile_func(FILE *fp,
503                                                   const Eina_Log_Domain *d,
504                                                   Eina_Log_Level level,
505                                                   const char *file __UNUSED__,
506                                                   const char *fnc,
507                                                   int line __UNUSED__)
508 {
509    DECLARE_LEVEL_NAME_COLOR(level);
510 #ifdef _WIN32_WCE
511    fprintf(fp, "%s<%u>:%s %s() ", name, eina_log_pid_get(), d->domain_str, 
512            fnc);
513 #elif _WIN32
514    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
515                            color);
516    fprintf(fp, "%s", name);
517    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
518                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
519    fprintf(fp, ":");
520    SetConsoleTextAttribute(GetStdHandle(
521                               STD_OUTPUT_HANDLE),
522                            eina_log_win32_color_get(d->domain_str));
523    fprintf(fp, "%s", d->name);
524    SetConsoleTextAttribute(GetStdHandle(
525                               STD_OUTPUT_HANDLE),
526                            FOREGROUND_INTENSITY | FOREGROUND_RED |
527                            FOREGROUND_GREEN | FOREGROUND_BLUE);
528    fprintf(fp, "%s()", fnc);
529    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
530                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
531    fprintf(fp, " ");
532 #else
533    fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s "
534            EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
535            color, name, eina_log_pid_get(), d->domain_str, fnc);
536 #endif
537 }
538
539 static void
540 eina_log_print_prefix_NOthreads_color_file_NOfunc(FILE *fp,
541                                                   const Eina_Log_Domain *d,
542                                                   Eina_Log_Level level,
543                                                   const char *file,
544                                                   const char *fnc __UNUSED__,
545                                                   int line)
546 {
547    DECLARE_LEVEL_NAME_COLOR(level);
548 #ifdef _WIN32_WCE
549    fprintf(fp, "%s<%u>:%s %s:%d ", name, eina_log_pid_get(), d->domain_str, 
550            file, line);
551 #elif _WIN32
552    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
553                            color);
554    fprintf(fp, "%s", name);
555    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
556                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
557    fprintf(fp, ":");
558    SetConsoleTextAttribute(GetStdHandle(
559                               STD_OUTPUT_HANDLE),
560                            eina_log_win32_color_get(d->domain_str));
561    fprintf(fp, "%s", d->name);
562    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
563                            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
564    fprintf(fp, " %s:%d ", file, line);
565 #else
566    fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s %s:%d ",
567            color, name, eina_log_pid_get(), d->domain_str, file, line);
568 #endif
569 }
570
571 /** threads, No color */
572 #ifdef EFL_HAVE_THREADS
573 static void
574 eina_log_print_prefix_threads_NOcolor_file_func(FILE *fp,
575                                                 const Eina_Log_Domain *d,
576                                                 Eina_Log_Level level,
577                                                 const char *file,
578                                                 const char *fnc,
579                                                 int line)
580 {
581    Thread cur;
582
583    DECLARE_LEVEL_NAME(level);
584    cur = SELF();
585    if (IS_OTHER(cur))
586      {
587         fprintf(fp, "%s<%u>:%s[T:%lu] %s:%d %s() ",
588                 name, eina_log_pid_get(), d->domain_str, 
589                 (unsigned long)cur, file, line, fnc);
590         return;
591      }
592    fprintf(fp, "%s<%u>:%s %s:%d %s() ", 
593            name, eina_log_pid_get(), d->domain_str, file, line, fnc);
594 }
595
596 static void
597 eina_log_print_prefix_threads_NOcolor_NOfile_func(FILE *fp,
598                                                   const Eina_Log_Domain *d,
599                                                   Eina_Log_Level level,
600                                                   const char *file __UNUSED__,
601                                                   const char *fnc,
602                                                   int line __UNUSED__)
603 {
604    Thread cur;
605
606    DECLARE_LEVEL_NAME(level);
607    cur = SELF();
608    if (IS_OTHER(cur))
609      {
610         fprintf(fp, "%s<%u>:%s[T:%lu] %s() ",
611                 name, eina_log_pid_get(), d->domain_str, 
612                 (unsigned long)cur, fnc);
613         return;
614      }
615    fprintf(fp, "%s<%u>:%s %s() ", 
616            name, eina_log_pid_get(), d->domain_str, fnc);
617 }
618
619 static void
620 eina_log_print_prefix_threads_NOcolor_file_NOfunc(FILE *fp,
621                                                   const Eina_Log_Domain *d,
622                                                   Eina_Log_Level level,
623                                                   const char *file,
624                                                   const char *fnc __UNUSED__,
625                                                   int line)
626 {
627    Thread cur;
628
629    DECLARE_LEVEL_NAME(level);
630    cur = SELF();
631    if (IS_OTHER(cur))
632      {
633         fprintf(fp, "%s<%u>:%s[T:%lu] %s:%d ",
634                 name, eina_log_pid_get(), d->domain_str, (unsigned long)cur, 
635                 file, line);
636         return;
637      }
638    
639    fprintf(fp, "%s<%u>:%s %s:%d ", 
640            name, eina_log_pid_get(), d->domain_str, file, line);
641 }
642
643 /* threads, color */
644 static void
645 eina_log_print_prefix_threads_color_file_func(FILE *fp,
646                                               const Eina_Log_Domain *d,
647                                               Eina_Log_Level level,
648                                               const char *file,
649                                               const char *fnc,
650                                               int line)
651 {
652    Thread cur;
653
654    DECLARE_LEVEL_NAME_COLOR(level);
655    cur = SELF();
656    if (IS_OTHER(cur))
657      {
658 # ifdef _WIN32
659         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
660                                 color);
661         fprintf(fp, "%s", name);
662         SetConsoleTextAttribute(GetStdHandle(
663                                    STD_OUTPUT_HANDLE),
664                                 FOREGROUND_RED | FOREGROUND_GREEN |
665                                 FOREGROUND_BLUE);
666         fprintf(fp, ":");
667         SetConsoleTextAttribute(GetStdHandle(
668                                    STD_OUTPUT_HANDLE),
669                                 eina_log_win32_color_get(d->domain_str));
670         fprintf(fp, "%s[T:", d->name);
671         SetConsoleTextAttribute(GetStdHandle(
672                                    STD_OUTPUT_HANDLE),
673                                 FOREGROUND_RED | FOREGROUND_GREEN |
674                                 FOREGROUND_BLUE);
675         fprintf(fp, "[T:");
676         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
677                                 FOREGROUND_GREEN | FOREGROUND_BLUE);
678         fprintf(fp, "%lu", (unsigned long)cur);
679         SetConsoleTextAttribute(GetStdHandle(
680                                    STD_OUTPUT_HANDLE),
681                                 FOREGROUND_RED | FOREGROUND_GREEN |
682                                 FOREGROUND_BLUE);
683         fprintf(fp, "] %s:%d ", file, line);
684         SetConsoleTextAttribute(GetStdHandle(
685                                    STD_OUTPUT_HANDLE),
686                                 FOREGROUND_INTENSITY | FOREGROUND_RED |
687                                 FOREGROUND_GREEN | FOREGROUND_BLUE);
688         fprintf(fp, "%s()", fnc);
689         SetConsoleTextAttribute(GetStdHandle(
690                                    STD_OUTPUT_HANDLE),
691                                 FOREGROUND_RED | FOREGROUND_GREEN |
692                                 FOREGROUND_BLUE);
693         fprintf(fp, " ");
694 # else
695         fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s[T:"
696                 EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] %s:%d "
697                 EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
698                 color, name, eina_log_pid_get() ,d->domain_str, 
699                 (unsigned long)cur, file, line, fnc);
700 # endif
701         return;
702      }
703
704 # ifdef _WIN32
705    eina_log_print_prefix_NOthreads_color_file_func(fp,
706                                                    d,
707                                                    level,
708                                                    file,
709                                                    fnc,
710                                                    line);
711 # else
712    fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s %s:%d "
713            EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
714            color, name, eina_log_pid_get(), d->domain_str, file, line, fnc);
715 # endif
716 }
717
718 static void
719 eina_log_print_prefix_threads_color_NOfile_func(FILE *fp,
720                                                 const Eina_Log_Domain *d,
721                                                 Eina_Log_Level level,
722                                                 const char *file __UNUSED__,
723                                                 const char *fnc,
724                                                 int line __UNUSED__)
725 {
726    Thread cur;
727
728    DECLARE_LEVEL_NAME_COLOR(level);
729    cur = SELF();
730    if (IS_OTHER(cur))
731      {
732 # ifdef _WIN32
733         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
734                                 color);
735         fprintf(fp, "%s", name);
736         SetConsoleTextAttribute(GetStdHandle(
737                                    STD_OUTPUT_HANDLE),
738                                 FOREGROUND_RED | FOREGROUND_GREEN |
739                                 FOREGROUND_BLUE);
740         fprintf(fp, ":");
741         SetConsoleTextAttribute(GetStdHandle(
742                                    STD_OUTPUT_HANDLE),
743                                 eina_log_win32_color_get(d->domain_str));
744         fprintf(fp, "%s[T:", d->name);
745         SetConsoleTextAttribute(GetStdHandle(
746                                    STD_OUTPUT_HANDLE),
747                                 FOREGROUND_RED | FOREGROUND_GREEN |
748                                 FOREGROUND_BLUE);
749         fprintf(fp, "[T:");
750         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
751                                 FOREGROUND_GREEN | FOREGROUND_BLUE);
752         fprintf(fp, "%lu", (unsigned long)cur);
753         SetConsoleTextAttribute(GetStdHandle(
754                                    STD_OUTPUT_HANDLE),
755                                 FOREGROUND_INTENSITY | FOREGROUND_RED |
756                                 FOREGROUND_GREEN | FOREGROUND_BLUE);
757         fprintf(fp, "%s()", fnc);
758         SetConsoleTextAttribute(GetStdHandle(
759                                    STD_OUTPUT_HANDLE),
760                                 FOREGROUND_RED | FOREGROUND_GREEN |
761                                 FOREGROUND_BLUE);
762         fprintf(fp, " ");
763 # else
764         fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s[T:"
765                 EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] "
766                 EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
767                 color, name, eina_log_pid_get(), d->domain_str, 
768                 (unsigned long)cur, fnc);
769 # endif
770         return;
771      }
772
773 # ifdef _WIN32
774    eina_log_print_prefix_NOthreads_color_NOfile_func(fp,
775                                                      d,
776                                                      level,
777                                                      file,
778                                                      fnc,
779                                                      line);
780 # else
781    fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s "
782            EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
783            color, name, eina_log_pid_get(), d->domain_str, fnc);
784 # endif
785 }
786
787 static void
788 eina_log_print_prefix_threads_color_file_NOfunc(FILE *fp,
789                                                 const Eina_Log_Domain *d,
790                                                 Eina_Log_Level level,
791                                                 const char *file,
792                                                 const char *fnc __UNUSED__,
793                                                 int line)
794 {
795    Thread cur;
796
797    DECLARE_LEVEL_NAME_COLOR(level);
798    cur = SELF();
799    if (IS_OTHER(cur))
800      {
801 # ifdef _WIN32
802         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
803                                 color);
804         fprintf(fp, "%s", name);
805         SetConsoleTextAttribute(GetStdHandle(
806                                    STD_OUTPUT_HANDLE),
807                                 FOREGROUND_RED | FOREGROUND_GREEN |
808                                 FOREGROUND_BLUE);
809         fprintf(fp, ":");
810         SetConsoleTextAttribute(GetStdHandle(
811                                    STD_OUTPUT_HANDLE),
812                                 eina_log_win32_color_get(d->domain_str));
813         fprintf(fp, "%s[T:", d->name);
814         SetConsoleTextAttribute(GetStdHandle(
815                                    STD_OUTPUT_HANDLE),
816                                 FOREGROUND_RED | FOREGROUND_GREEN |
817                                 FOREGROUND_BLUE);
818         fprintf(fp, "[T:");
819         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
820                                 FOREGROUND_GREEN | FOREGROUND_BLUE);
821         fprintf(fp, "%lu", (unsigned long)cur);
822         SetConsoleTextAttribute(GetStdHandle(
823                                    STD_OUTPUT_HANDLE),
824                                 FOREGROUND_RED | FOREGROUND_GREEN |
825                                 FOREGROUND_BLUE);
826         fprintf(fp, "] %s:%d ", file, line);
827 # else
828         fprintf(fp, "%s%s<%u>" EINA_COLOR_RESET ":%s[T:"
829                 EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] %s:%d ",
830                 color, name, eina_log_pid_get(), d->domain_str, 
831                 (unsigned long)cur, file, line);
832 # endif
833         return;
834      }
835
836 # ifdef _WIN32
837    eina_log_print_prefix_NOthreads_color_file_NOfunc(fp,
838                                                      d,
839                                                      level,
840                                                      file,
841                                                      fnc,
842                                                      line);
843 # else
844         fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s %s:%d ",
845            color, name, d->domain_str, file, line);
846 # endif
847 }
848 #endif /* EFL_HAVE_THREADS */
849
850 static void (*_eina_log_print_prefix)(FILE *fp, const Eina_Log_Domain *d,
851                                       Eina_Log_Level level, const char *file,
852                                       const char *fnc,
853                                       int line) =
854    eina_log_print_prefix_NOthreads_color_file_func;
855
856 static inline void
857 eina_log_print_prefix_update(void)
858 {
859    if (_disable_file && _disable_function)
860      {
861         fprintf(stderr, "ERROR: cannot have " EINA_LOG_ENV_FILE_DISABLE " and "
862                 EINA_LOG_ENV_FUNCTION_DISABLE " set at the same time, will "
863                                               "just disable function.\n");
864         _disable_file = 0;
865      }
866
867 #define S(NOthread, NOcolor, NOfile, NOfunc) \
868    _eina_log_print_prefix = \
869       eina_log_print_prefix_ ## NOthread ## threads_ ## NOcolor ## color_ ## \
870       NOfile \
871       ## file_ ## NOfunc ## func
872
873 #ifdef EFL_HAVE_THREADS
874    if (_threads_enabled)
875      {
876         if (_disable_color)
877           {
878              if (_disable_file)
879                 S(,NO,NO,);
880              else if (_disable_function)
881                 S(,NO,,NO);
882              else
883                 S(,NO,,);
884           }
885         else
886           {
887              if (_disable_file)
888                 S(,,NO,);
889              else if (_disable_function)
890                 S(,,,NO);
891              else
892                 S(,,,);
893           }
894
895         return;
896      }
897
898 #endif
899
900    if (_disable_color)
901      {
902         if (_disable_file)
903                 S(NO,NO,NO,);
904         else if (_disable_function)
905                 S(NO,NO,,NO);
906         else
907                 S(NO,NO,,);
908      }
909    else
910      {
911         if (_disable_file)
912                 S(NO,,NO,);
913         else if (_disable_function)
914                 S(NO,,,NO);
915         else
916                 S(NO,,,);
917      }
918
919 #undef S
920 }
921
922 /*
923  * Creates a colored domain name string.
924  */
925 static const char *
926 eina_log_domain_str_get(const char *name, const char *color)
927 {
928    const char *d;
929
930    if (color)
931      {
932         size_t name_len;
933         size_t color_len;
934
935         name_len = strlen(name);
936         color_len = strlen(color);
937         d =
938            malloc(sizeof(char) *
939                   (color_len + name_len + strlen(EINA_COLOR_RESET) + 1));
940         if (!d)
941            return NULL;
942
943                memcpy((char *)d,                          color, color_len);
944                memcpy((char *)(d + color_len),            name,  name_len);
945                memcpy((char *)(d + color_len + name_len), EINA_COLOR_RESET,
946                strlen(EINA_COLOR_RESET));
947         ((char *)d)[color_len + name_len + strlen(EINA_COLOR_RESET)] = '\0';
948      }
949    else
950       d = strdup(name);
951
952    return d;
953 }
954
955 /*
956  * Setups a new logging domain to the name and color specified. Note that this
957  * constructor acts upon an pre-allocated object.
958  */
959 static Eina_Log_Domain *
960 eina_log_domain_new(Eina_Log_Domain *d, const char *name, const char *color)
961 {
962    EINA_SAFETY_ON_NULL_RETURN_VAL(d,    NULL);
963    EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
964
965    d->level = EINA_LOG_LEVEL_UNKNOWN;
966    d->deleted = EINA_FALSE;
967
968    if ((color) && (!_disable_color))
969       d->domain_str = eina_log_domain_str_get(name, color);
970    else
971       d->domain_str = eina_log_domain_str_get(name, NULL);
972
973    d->name = strdup(name);
974    d->namelen = strlen(name);
975
976    return d;
977 }
978
979 /*
980  * Frees internal strings of a log domain, keeping the log domain itself as a
981  * slot for next domain registers.
982  */
983 static void
984 eina_log_domain_free(Eina_Log_Domain *d)
985 {
986    EINA_SAFETY_ON_NULL_RETURN(d);
987
988    if (d->domain_str)
989       free((char *)d->domain_str);
990
991    if (d->name)
992       free((char *)d->name);
993 }
994
995 /*
996  * Parses domain levels passed through the env var.
997  */
998 static void
999 eina_log_domain_parse_pendings(void)
1000 {
1001    const char *start;
1002
1003    if (!(start = getenv(EINA_LOG_ENV_LEVELS)))
1004       return;
1005
1006    // name1:level1,name2:level2,name3:level3,...
1007    while (1)
1008      {
1009         Eina_Log_Domain_Level_Pending *p;
1010         char *end = NULL;
1011         char *tmp = NULL;
1012         long int level;
1013
1014         end = strchr(start, ':');
1015         if (!end)
1016            break;
1017
1018         // Parse level, keep going if failed
1019         level = strtol((char *)(end + 1), &tmp, 10);
1020         if (tmp == (end + 1))
1021            goto parse_end;
1022
1023         // Parse name
1024         p = malloc(sizeof(Eina_Log_Domain_Level_Pending) + end - start + 1);
1025         if (!p)
1026            break;
1027
1028         p->namelen = end - start;
1029         memcpy((char *)p->name, start, end - start);
1030         ((char *)p->name)[end - start] = '\0';
1031         p->level = level;
1032
1033         _pending_list = eina_inlist_append(_pending_list, EINA_INLIST_GET(p));
1034
1035 parse_end:
1036         start = strchr(tmp, ',');
1037         if (start)
1038            start++;
1039         else
1040            break;
1041      }
1042 }
1043
1044 static void
1045 eina_log_domain_parse_pending_globs(void)
1046 {
1047    const char *start;
1048
1049    if (!(start = getenv(EINA_LOG_ENV_LEVELS_GLOB)))
1050       return;
1051
1052    // name1:level1,name2:level2,name3:level3,...
1053    while (1)
1054      {
1055         Eina_Log_Domain_Level_Pending *p;
1056         char *end = NULL;
1057         char *tmp = NULL;
1058         long int level;
1059
1060         end = strchr(start, ':');
1061         if (!end)
1062            break;
1063
1064         // Parse level, keep going if failed
1065         level = strtol((char *)(end + 1), &tmp, 10);
1066         if (tmp == (end + 1))
1067            goto parse_end;
1068
1069         // Parse name
1070         p = malloc(sizeof(Eina_Log_Domain_Level_Pending) + end - start + 1);
1071         if (!p)
1072            break;
1073
1074         p->namelen = 0; /* not that useful */
1075         memcpy((char *)p->name, start, end - start);
1076         ((char *)p->name)[end - start] = '\0';
1077         p->level = level;
1078
1079         _glob_list = eina_inlist_append(_glob_list, EINA_INLIST_GET(p));
1080
1081 parse_end:
1082         start = strchr(tmp, ',');
1083         if (start)
1084            start++;
1085         else
1086            break;
1087      }
1088 }
1089
1090 static inline int
1091 eina_log_domain_register_unlocked(const char *name, const char *color)
1092 {
1093    Eina_Log_Domain_Level_Pending *pending = NULL;
1094    size_t namelen;
1095    unsigned int i;
1096
1097    for (i = 0; i < _log_domains_count; i++)
1098      {
1099         if (_log_domains[i].deleted)
1100           {
1101              // Found a flagged slot, free domain_str and replace slot
1102              eina_log_domain_new(&_log_domains[i], name, color);
1103              goto finish_register;
1104           }
1105      }
1106
1107    if (_log_domains_count >= _log_domains_allocated)
1108      {
1109         Eina_Log_Domain *tmp;
1110         size_t size;
1111
1112         if (!_log_domains)
1113            // special case for init, eina itself will allocate a dozen of domains
1114            size = 24;
1115         else
1116            // grow 8 buckets to minimize reallocs
1117            size = _log_domains_allocated + 8;
1118
1119         tmp = realloc(_log_domains, sizeof(Eina_Log_Domain) * size);
1120
1121         if (tmp)
1122           {
1123              // Success!
1124              _log_domains = tmp;
1125              _log_domains_allocated = size;
1126           }
1127         else
1128            return -1;
1129      }
1130
1131    // Use an allocated slot
1132              eina_log_domain_new(&_log_domains[i], name, color);
1133    _log_domains_count++;
1134
1135 finish_register:
1136    namelen = _log_domains[i].namelen;
1137
1138    EINA_INLIST_FOREACH(_pending_list, pending)
1139    {
1140       if ((namelen == pending->namelen) && (strcmp(pending->name, name) == 0))
1141         {
1142            _log_domains[i].level = pending->level;
1143            _pending_list =
1144               eina_inlist_remove(_pending_list, EINA_INLIST_GET(pending));
1145            free(pending);
1146            break;
1147         }
1148    }
1149
1150    if (_log_domains[i].level == EINA_LOG_LEVEL_UNKNOWN)
1151      {
1152         EINA_INLIST_FOREACH(_glob_list, pending)
1153         {
1154            if (!fnmatch(pending->name, name, 0))
1155              {
1156                 _log_domains[i].level = pending->level;
1157                 break;
1158              }
1159         }
1160      }
1161
1162    // Check if level is still UNKNOWN, set it to global
1163    if (_log_domains[i].level == EINA_LOG_LEVEL_UNKNOWN)
1164       _log_domains[i].level = _log_level;
1165
1166    return i;
1167 }
1168
1169 static inline Eina_Bool
1170 eina_log_term_color_supported(const char *term)
1171 {
1172    const char *tail;
1173
1174    if (!term)
1175       return EINA_FALSE;
1176
1177    tail = term + 1;
1178    switch (term[0])
1179      {
1180       /* list of known to support color terminals,
1181        * take from gentoo's portage.
1182        */
1183
1184       case 'x': /* xterm and xterm-color */
1185          return ((strncmp(tail, "term", sizeof("term") - 1) == 0) &&
1186                  ((tail[sizeof("term") - 1] == '\0') ||
1187                   (strcmp(tail + sizeof("term") - 1, "-color") == 0)));
1188
1189       case 'E': /* Eterm */
1190       case 'a': /* aterm */
1191       case 'k': /* kterm */
1192          return (strcmp(tail, "term") == 0);
1193
1194       case 'r': /* xrvt or rxvt-unicode */
1195          return ((strncmp(tail, "xvt", sizeof("xvt") - 1) == 0) &&
1196                  ((tail[sizeof("xvt") - 1] == '\0') ||
1197                   (strcmp(tail + sizeof("xvt") - 1, "-unicode") == 0)));
1198
1199       case 's': /* screen */
1200          return (strcmp(tail, "creen") == 0);
1201
1202       case 'g': /* gnome */
1203          return (strcmp(tail, "nome") == 0);
1204
1205       case 'i': /* interix */
1206          return (strcmp(tail, "nterix") == 0);
1207
1208       default:
1209          return EINA_FALSE;
1210      }
1211 }
1212
1213 static inline void
1214 eina_log_domain_unregister_unlocked(int domain)
1215 {
1216    Eina_Log_Domain *d;
1217
1218    if ((unsigned int)domain >= _log_domains_count)
1219       return;
1220
1221    d = &_log_domains[domain];
1222    eina_log_domain_free(d);
1223    d->deleted = 1;
1224 }
1225
1226 static inline void
1227 eina_log_print_unlocked(int domain,
1228                         Eina_Log_Level level,
1229                         const char *file,
1230                         const char *fnc,
1231                         int line,
1232                         const char *fmt,
1233                         va_list args)
1234 {
1235    Eina_Log_Domain *d;
1236
1237 #ifdef EINA_SAFETY_CHECKS
1238    if (EINA_UNLIKELY((unsigned int)domain >= _log_domains_count) ||
1239        EINA_UNLIKELY(domain < 0))
1240      {
1241         if (file && fnc && fmt)
1242            fprintf(
1243               stderr,
1244               "CRI: %s:%d %s() eina_log_print() unknown domain %d, original message format '%s'\n",
1245               file,
1246               line,
1247               fnc,
1248               domain,
1249               fmt);
1250         else
1251            fprintf(
1252               stderr,
1253               "CRI: eina_log_print() unknown domain %d, original message format '%s'\n",
1254               domain,
1255               fmt ? fmt : "");
1256
1257         if (_abort_on_critical)
1258            abort();
1259
1260         return;
1261      }
1262
1263 #endif
1264    d = _log_domains + domain;
1265 #ifdef EINA_SAFETY_CHECKS
1266    if (EINA_UNLIKELY(d->deleted))
1267      {
1268            fprintf(stderr,
1269                 "ERR: eina_log_print() domain %d is deleted\n",
1270                 domain);
1271         return;
1272      }
1273
1274 #endif
1275
1276    if (level > d->level)
1277       return;
1278
1279 #ifdef _WIN32
1280    {
1281       char *wfmt;
1282       char *tmp;
1283
1284       wfmt = strdup(fmt);
1285       if (!wfmt)
1286         {
1287            fprintf(stderr, "ERR: %s: can not allocate memory\n", __FUNCTION__);
1288            return;
1289         }
1290
1291       tmp = wfmt;
1292       while (strchr(tmp, '%'))
1293         {
1294            tmp++;
1295            if (*tmp == 'z')
1296               *tmp = 'I';
1297         }
1298       _print_cb(d, level, file, fnc, line, wfmt, _print_cb_data, args);
1299       free(wfmt);
1300    }
1301 #else
1302    _print_cb(d, level, file, fnc, line, fmt, _print_cb_data, args);
1303 #endif
1304
1305    if (EINA_UNLIKELY(_abort_on_critical) &&
1306        EINA_UNLIKELY(level <= _abort_level_on_critical))
1307       abort();
1308 }
1309
1310 #endif
1311
1312 /**
1313  * @endcond
1314  */
1315
1316
1317 /*============================================================================*
1318 *                                 Global                                     *
1319 *============================================================================*/
1320
1321 /**
1322  * @internal
1323  * @brief Initialize the log module.
1324  *
1325  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
1326  *
1327  * This function sets up the log module of Eina. It is called by
1328  * eina_init().
1329  *
1330  * @see eina_init()
1331  *
1332  * @warning Not-MT: just call this function from main thread! The
1333  *          place where this function was called the first time is
1334  *          considered the main thread.
1335  */
1336 Eina_Bool
1337 eina_log_init(void)
1338 {
1339 #ifdef EINA_ENABLE_LOG
1340    const char *level, *tmp;
1341    int color_disable;
1342
1343    assert((sizeof(_names) / sizeof(_names[0])) == EINA_LOG_LEVELS);
1344
1345 #ifdef EINA_LOG_BACKTRACE
1346    if ((tmp = getenv(EINA_LOG_ENV_BACKTRACE)))
1347      _backtrace_level = atoi(tmp);
1348 #endif
1349
1350    if ((tmp = getenv(EINA_LOG_ENV_COLOR_DISABLE)))
1351       color_disable = atoi(tmp);
1352    else
1353       color_disable = -1;
1354
1355    /* Check if color is explicitly disabled */
1356    if (color_disable == 1)
1357       _disable_color = EINA_TRUE;
1358
1359 #ifndef _WIN32
1360    /* color was not explicitly disabled or enabled, guess it */
1361    else if (color_disable == -1)
1362      {
1363         if (!eina_log_term_color_supported(getenv("TERM")))
1364            _disable_color = EINA_TRUE;
1365         else
1366           {
1367              /* if not a terminal, but redirected to a file, disable color */
1368              int fd;
1369
1370              if (_print_cb == eina_log_print_cb_stderr)
1371                 fd = STDERR_FILENO;
1372              else if (_print_cb == eina_log_print_cb_stdout)
1373                 fd = STDOUT_FILENO;
1374              else
1375                 fd = -1;
1376
1377              if ((fd >= 0) && (!isatty(fd)))
1378                 _disable_color = EINA_TRUE;
1379           }
1380      }
1381 #endif
1382
1383    if ((tmp = getenv(EINA_LOG_ENV_FILE_DISABLE)) && (atoi(tmp) == 1))
1384       _disable_file = EINA_TRUE;
1385
1386    if ((tmp = getenv(EINA_LOG_ENV_FUNCTION_DISABLE)) && (atoi(tmp) == 1))
1387       _disable_function = EINA_TRUE;
1388
1389    if ((tmp = getenv(EINA_LOG_ENV_ABORT)) && (atoi(tmp) == 1))
1390       _abort_on_critical = EINA_TRUE;
1391
1392    if ((tmp = getenv(EINA_LOG_ENV_ABORT_LEVEL)))
1393       _abort_level_on_critical = atoi(tmp);
1394
1395    eina_log_print_prefix_update();
1396
1397    // Global log level
1398    if ((level = getenv(EINA_LOG_ENV_LEVEL)))
1399       _log_level = atoi(level);
1400
1401    // Register UNKNOWN domain, the default logger
1402    EINA_LOG_DOMAIN_GLOBAL = eina_log_domain_register("", NULL);
1403
1404    if (EINA_LOG_DOMAIN_GLOBAL < 0)
1405      {
1406         fprintf(stderr, "Failed to create global logging domain.\n");
1407         return EINA_FALSE;
1408      }
1409
1410    // Parse pending domains passed through EINA_LOG_LEVELS_GLOB
1411    eina_log_domain_parse_pending_globs();
1412
1413    // Parse pending domains passed through EINA_LOG_LEVELS
1414    eina_log_domain_parse_pendings();
1415
1416 #endif
1417    return EINA_TRUE;
1418 }
1419
1420 /**
1421  * @internal
1422  * @brief Shut down the log module.
1423  *
1424  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
1425  *
1426  * This function shuts down the log module set up by
1427  * eina_log_init(). It is called by eina_shutdown().
1428  *
1429  * @see eina_shutdown()
1430  *
1431  * @warning Not-MT: just call this function from main thread! The
1432  *          place where eina_log_init() (eina_init()) was called the
1433  *          first time is considered the main thread.
1434  */
1435 Eina_Bool
1436 eina_log_shutdown(void)
1437 {
1438 #ifdef EINA_ENABLE_LOG
1439    Eina_Inlist *tmp;
1440
1441    while (_log_domains_count--)
1442      {
1443         if (_log_domains[_log_domains_count].deleted)
1444            continue;
1445
1446         eina_log_domain_free(&_log_domains[_log_domains_count]);
1447      }
1448
1449         free(_log_domains);
1450
1451    _log_domains = NULL;
1452    _log_domains_count = 0;
1453    _log_domains_allocated = 0;
1454
1455    while (_glob_list)
1456      {
1457         tmp = _glob_list;
1458         _glob_list = _glob_list->next;
1459         free(tmp);
1460      }
1461
1462    while (_pending_list)
1463      {
1464         tmp = _pending_list;
1465         _pending_list = _pending_list->next;
1466         free(tmp);
1467      }
1468
1469 #endif
1470    return EINA_TRUE;
1471 }
1472
1473 #ifdef EFL_HAVE_THREADS
1474
1475 /**
1476  * @internal
1477  * @brief Activate the log mutex.
1478  *
1479  * This function activate the mutex in the eina log module. It is called by
1480  * eina_threads_init().
1481  *
1482  * @see eina_threads_init()
1483  */
1484 void
1485 eina_log_threads_init(void)
1486 {
1487 #ifdef EINA_ENABLE_LOG
1488    if (_threads_inited) return;
1489    _main_thread = SELF();
1490    if (!INIT()) return;
1491    _threads_inited = EINA_TRUE;
1492 #endif
1493 }
1494
1495 /**
1496  * @internal
1497  * @brief Shut down the log mutex.
1498  *
1499  * This function shuts down the mutex in the log module.
1500  * It is called by eina_threads_shutdown().
1501  *
1502  * @see eina_threads_shutdown()
1503  */
1504 void
1505 eina_log_threads_shutdown(void)
1506 {
1507 #ifdef EINA_ENABLE_LOG
1508    if (!_threads_inited) return;
1509    CHECK_MAIN();
1510    SHUTDOWN();
1511    _threads_enabled = EINA_FALSE;
1512    _threads_inited = EINA_FALSE;
1513 #endif
1514 }
1515
1516 #endif
1517
1518 /*============================================================================*
1519 *                                   API                                      *
1520 *============================================================================*/
1521
1522 /**
1523  * @cond LOCAL
1524  */
1525
1526 EAPI int EINA_LOG_DOMAIN_GLOBAL = 0;
1527
1528 /**
1529  * @endcond
1530  */
1531
1532 EAPI void
1533 eina_log_threads_enable(void)
1534 {
1535 #if defined (EFL_HAVE_THREADS) && defined (EINA_ENABLE_LOG)
1536    if (_threads_enabled) return;
1537    if (!_threads_inited) eina_log_threads_init();
1538    _threads_enabled = EINA_TRUE;
1539    eina_log_print_prefix_update();
1540 #endif
1541 }
1542
1543 EAPI void
1544 eina_log_print_cb_set(Eina_Log_Print_Cb cb, void *data)
1545 {
1546 #ifdef EINA_ENABLE_LOG
1547    LOG_LOCK();
1548    _print_cb = cb;
1549    _print_cb_data = data;
1550    eina_log_print_prefix_update();
1551    LOG_UNLOCK();
1552 #else
1553    (void) cb;
1554    (void) data;
1555 #endif
1556 }
1557
1558 EAPI void
1559 eina_log_level_set(int level)
1560 {
1561 #ifdef EINA_ENABLE_LOG
1562    _log_level = level;
1563    if (EINA_LIKELY((EINA_LOG_DOMAIN_GLOBAL >= 0) &&
1564                    ((unsigned int)EINA_LOG_DOMAIN_GLOBAL < _log_domains_count)))
1565       _log_domains[EINA_LOG_DOMAIN_GLOBAL].level = level;
1566 #else
1567    (void) level;
1568 #endif
1569 }
1570
1571 EAPI int
1572 eina_log_level_get(void)
1573 {
1574 #ifdef EINA_ENABLE_LOG
1575    return _log_level;
1576 #else
1577    return 0;
1578 #endif
1579 }
1580
1581 EAPI Eina_Bool
1582 eina_log_main_thread_check(void)
1583 {
1584 #if defined (EFL_HAVE_THREADS) && defined (EINA_ENABLE_LOG)
1585    return ((!_threads_enabled) || IS_MAIN(SELF()));
1586 #else
1587    return EINA_TRUE;
1588 #endif
1589 }
1590
1591 EAPI void
1592 eina_log_color_disable_set(Eina_Bool disabled)
1593 {
1594 #ifdef EINA_ENABLE_LOG
1595    _disable_color = disabled;
1596 #else
1597    (void) disabled;
1598 #endif
1599 }
1600
1601 EAPI Eina_Bool
1602 eina_log_color_disable_get(void)
1603 {
1604 #ifdef EINA_ENABLE_LOG
1605    return _disable_color;
1606 #else
1607    return EINA_TRUE;
1608 #endif
1609 }
1610
1611 EAPI void
1612 eina_log_file_disable_set(Eina_Bool disabled)
1613 {
1614 #ifdef EINA_ENABLE_LOG
1615    _disable_file = disabled;
1616 #else
1617    (void) disabled;
1618 #endif
1619 }
1620
1621 EAPI Eina_Bool
1622 eina_log_file_disable_get(void)
1623 {
1624 #ifdef EINA_ENABLE_LOG
1625    return _disable_file;
1626 #else
1627    return EINA_TRUE;
1628 #endif
1629 }
1630
1631 EAPI void
1632 eina_log_function_disable_set(Eina_Bool disabled)
1633 {
1634 #ifdef EINA_ENABLE_LOG
1635    _disable_function = disabled;
1636 #else
1637    (void) disabled;
1638 #endif
1639 }
1640
1641 EAPI Eina_Bool
1642 eina_log_function_disable_get(void)
1643 {
1644 #ifdef EINA_ENABLE_LOG
1645    return _disable_function;
1646 #else
1647    return EINA_TRUE;
1648 #endif
1649 }
1650
1651 EAPI void
1652 eina_log_abort_on_critical_set(Eina_Bool abort_on_critical)
1653 {
1654 #ifdef EINA_ENABLE_LOG
1655    _abort_on_critical = abort_on_critical;
1656 #else
1657    (void) abort_on_critical;
1658 #endif
1659 }
1660
1661 EAPI Eina_Bool
1662 eina_log_abort_on_critical_get(void)
1663 {
1664 #ifdef EINA_ENABLE_LOG
1665    return _abort_on_critical;
1666 #else
1667    return EINA_FALSE;
1668 #endif
1669 }
1670
1671 EAPI void
1672 eina_log_abort_on_critical_level_set(int critical_level)
1673 {
1674 #ifdef EINA_ENABLE_LOG
1675    _abort_level_on_critical = critical_level;
1676 #else
1677    (void) critical_level;
1678 #endif
1679 }
1680
1681 EAPI int
1682 eina_log_abort_on_critical_level_get(void)
1683 {
1684 #ifdef EINA_ENABLE_LOG
1685    return _abort_level_on_critical;
1686 #else
1687    return 0;
1688 #endif
1689 }
1690
1691 EAPI int
1692 eina_log_domain_register(const char *name, const char *color)
1693 {
1694 #ifdef EINA_ENABLE_LOG
1695    int r;
1696
1697    EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1);
1698
1699    LOG_LOCK();
1700    r = eina_log_domain_register_unlocked(name, color);
1701    LOG_UNLOCK();
1702    return r;
1703 #else
1704    (void) name;
1705    (void) color;
1706    return 0;
1707 #endif
1708 }
1709
1710 EAPI void
1711 eina_log_domain_unregister(int domain)
1712 {
1713 #ifdef EINA_ENABLE_LOG
1714    EINA_SAFETY_ON_FALSE_RETURN(domain >= 0);
1715    LOG_LOCK();
1716    eina_log_domain_unregister_unlocked(domain);
1717    LOG_UNLOCK();
1718 #else
1719    (void) domain;
1720 #endif
1721 }
1722
1723 EAPI void
1724 eina_log_domain_level_set(const char *domain_name, int level)
1725 {
1726 #ifdef EINA_ENABLE_LOG
1727    Eina_Log_Domain_Level_Pending *pending;
1728    size_t namelen;
1729    unsigned int i;
1730
1731    EINA_SAFETY_ON_NULL_RETURN(domain_name);
1732
1733    namelen = strlen(domain_name);
1734
1735    for (i = 0; i < _log_domains_count; i++)
1736      {
1737         if (_log_domains[i].deleted)
1738            continue;
1739
1740         if ((namelen != _log_domains[i].namelen) ||
1741             (strcmp(_log_domains[i].name, domain_name) != 0))
1742            continue;
1743
1744         _log_domains[i].level = level;
1745         return;
1746      }
1747
1748    EINA_INLIST_FOREACH(_pending_list, pending)
1749    {
1750       if ((namelen == pending->namelen) &&
1751           (strcmp(pending->name, domain_name) == 0))
1752         {
1753            pending->level = level;
1754            return;
1755         }
1756    }
1757
1758    pending = malloc(sizeof(Eina_Log_Domain_Level_Pending) + namelen + 1);
1759    if (!pending)
1760       return;
1761
1762    pending->level = level;
1763    pending->namelen = namelen;
1764    memcpy(pending->name, domain_name, namelen + 1);
1765
1766    _pending_list = eina_inlist_append(_pending_list, EINA_INLIST_GET(pending));
1767 #else
1768    (void) domain_name;
1769    (void) level;
1770 #endif
1771 }
1772
1773 EAPI int
1774 eina_log_domain_level_get(const char *domain_name)
1775 {
1776 #ifdef EINA_ENABLE_LOG
1777    Eina_Log_Domain_Level_Pending *pending;
1778    size_t namelen;
1779    unsigned int i;
1780
1781    EINA_SAFETY_ON_NULL_RETURN_VAL(domain_name, EINA_LOG_LEVEL_UNKNOWN);
1782
1783    namelen = strlen(domain_name);
1784
1785    for (i = 0; i < _log_domains_count; i++)
1786      {
1787         if (_log_domains[i].deleted)
1788            continue;
1789
1790         if ((namelen != _log_domains[i].namelen) ||
1791             (strcmp(_log_domains[i].name, domain_name) != 0))
1792            continue;
1793
1794         return _log_domains[i].level;
1795      }
1796
1797    EINA_INLIST_FOREACH(_pending_list, pending)
1798    {
1799       if ((namelen == pending->namelen) &&
1800           (strcmp(pending->name, domain_name) == 0))
1801          return pending->level;
1802    }
1803
1804    EINA_INLIST_FOREACH(_glob_list, pending)
1805    {
1806       if (!fnmatch(pending->name, domain_name, 0))
1807          return pending->level;
1808    }
1809
1810    return _log_level;
1811 #else
1812    (void) domain_name;
1813    return 0;
1814 #endif
1815 }
1816
1817 EAPI int
1818 eina_log_domain_registered_level_get(int domain)
1819 {
1820 #ifdef EINA_ENABLE_LOG
1821    EINA_SAFETY_ON_FALSE_RETURN_VAL(domain >= 0, EINA_LOG_LEVEL_UNKNOWN);
1822    EINA_SAFETY_ON_FALSE_RETURN_VAL((unsigned int)domain < _log_domains_count,
1823                                    EINA_LOG_LEVEL_UNKNOWN);
1824    EINA_SAFETY_ON_TRUE_RETURN_VAL(_log_domains[domain].deleted,
1825                                   EINA_LOG_LEVEL_UNKNOWN);
1826    return _log_domains[domain].level;
1827 #else
1828    (void) domain;
1829    return 0;
1830 #endif
1831 }
1832
1833 #ifdef EINA_LOG_BACKTRACE
1834 # define DISPLAY_BACKTRACE(File, Level)                 \
1835   if (EINA_UNLIKELY(Level < _backtrace_level))          \
1836     {                                                   \
1837       void *bt[256];                                    \
1838       char **strings;                                   \
1839       int btlen;                                        \
1840       int i;                                            \
1841                                                         \
1842       btlen = backtrace((void **)bt, 256);              \
1843       strings = backtrace_symbols((void **)bt, btlen);  \
1844       fprintf(File, "*** Backtrace ***\n");             \
1845       for (i = 0; i < btlen; ++i)                       \
1846         fprintf(File, "%s\n", strings[i]);              \
1847       free(strings);                                    \
1848     }
1849 #else
1850 # define DISPLAY_BACKTRACE(File, Level)
1851 #endif
1852
1853 EAPI void
1854 eina_log_print_cb_stderr(const Eina_Log_Domain *d,
1855                          Eina_Log_Level level,
1856                          const char *file,
1857                          const char *fnc,
1858                          int line,
1859                          const char *fmt,
1860                          __UNUSED__ void *data,
1861                          va_list args)
1862 {
1863 #ifdef EINA_ENABLE_LOG
1864    _eina_log_print_prefix(stderr, d, level, file, fnc, line);
1865    vfprintf(stderr, fmt, args);
1866    putc('\n', stderr);
1867    DISPLAY_BACKTRACE(stderr, level);
1868 #else
1869    (void) d;
1870    (void) level;
1871    (void) file;
1872    (void) fnc;
1873    (void) line;
1874    (void) fmt;
1875    (void) data;
1876    (void) args;
1877 #endif
1878 }
1879
1880 EAPI void
1881 eina_log_print_cb_stdout(const Eina_Log_Domain *d,
1882                          Eina_Log_Level level,
1883                          const char *file,
1884                          const char *fnc,
1885                          int line,
1886                          const char *fmt,
1887                          __UNUSED__ void *data,
1888                          va_list args)
1889 {
1890 #ifdef EINA_ENABLE_LOG
1891    _eina_log_print_prefix(stdout, d, level, file, fnc, line);
1892    vprintf(fmt, args);
1893    putchar('\n');
1894    DISPLAY_BACKTRACE(stdout, level);
1895 #else
1896    (void) d;
1897    (void) level;
1898    (void) file;
1899    (void) fnc;
1900    (void) line;
1901    (void) fmt;
1902    (void) data;
1903    (void) args;
1904 #endif
1905 }
1906
1907 EAPI void
1908 eina_log_print_cb_file(const Eina_Log_Domain *d,
1909                        __UNUSED__ Eina_Log_Level level,
1910                        const char *file,
1911                        const char *fnc,
1912                        int line,
1913                        const char *fmt,
1914                        void *data,
1915                        va_list args)
1916 {
1917 #ifdef EINA_ENABLE_LOG
1918    FILE *f = data;
1919 #ifdef EFL_HAVE_THREADS
1920    if (_threads_enabled)
1921      {
1922         Thread cur;
1923
1924         cur = SELF();
1925         if (IS_OTHER(cur))
1926           {
1927              fprintf(f, "%s[T:%lu] %s:%d %s() ", d->name, (unsigned long)cur,
1928                 file, line, fnc);
1929              goto end;
1930           }
1931      }
1932
1933 #endif
1934    fprintf(f, "%s<%u> %s:%d %s() ", d->name, eina_log_pid_get(), 
1935            file, line, fnc);
1936    DISPLAY_BACKTRACE(f, level);
1937 #ifdef EFL_HAVE_THREADS
1938 end:
1939 #endif
1940    vfprintf(f, fmt, args);
1941    putc('\n', f);
1942 #else
1943    (void) d;
1944    (void) file;
1945    (void) fnc;
1946    (void) line;
1947    (void) fmt;
1948    (void) data;
1949    (void) args;
1950 #endif
1951 }
1952
1953 EAPI void
1954 eina_log_print(int domain, Eina_Log_Level level, const char *file,
1955                const char *fnc, int line, const char *fmt, ...)
1956 {
1957 #ifdef EINA_ENABLE_LOG
1958    va_list args;
1959
1960 #ifdef EINA_SAFETY_CHECKS
1961    if (EINA_UNLIKELY(!file))
1962      {
1963         fputs("ERR: eina_log_print() file == NULL\n", stderr);
1964         return;
1965      }
1966
1967    if (EINA_UNLIKELY(!fnc))
1968      {
1969         fputs("ERR: eina_log_print() fnc == NULL\n", stderr);
1970         return;
1971      }
1972
1973    if (EINA_UNLIKELY(!fmt))
1974      {
1975         fputs("ERR: eina_log_print() fmt == NULL\n", stderr);
1976         return;
1977      }
1978
1979 #endif
1980    va_start(args, fmt);
1981    LOG_LOCK();
1982    eina_log_print_unlocked(domain, level, file, fnc, line, fmt, args);
1983    LOG_UNLOCK();
1984    va_end(args);
1985 #else
1986    (void) domain;
1987    (void) level;
1988    (void) file;
1989    (void) fnc;
1990    (void) line;
1991    (void) fmt;
1992 #endif
1993 }
1994
1995 EAPI void
1996 eina_log_vprint(int domain, Eina_Log_Level level, const char *file,
1997                 const char *fnc, int line, const char *fmt, va_list args)
1998 {
1999 #ifdef EINA_ENABLE_LOG
2000
2001 #ifdef EINA_SAFETY_CHECKS
2002    if (EINA_UNLIKELY(!file))
2003      {
2004         fputs("ERR: eina_log_print() file == NULL\n", stderr);
2005         return;
2006      }
2007
2008    if (EINA_UNLIKELY(!fnc))
2009      {
2010         fputs("ERR: eina_log_print() fnc == NULL\n", stderr);
2011         return;
2012      }
2013
2014    if (EINA_UNLIKELY(!fmt))
2015      {
2016         fputs("ERR: eina_log_print() fmt == NULL\n", stderr);
2017         return;
2018      }
2019
2020 #endif
2021    LOG_LOCK();
2022    eina_log_print_unlocked(domain, level, file, fnc, line, fmt, args);
2023    LOG_UNLOCK();
2024 #else
2025    (void) domain;
2026    (void) level;
2027    (void) file;
2028    (void) fnc;
2029    (void) line;
2030    (void) fmt;
2031    (void) args;
2032 #endif
2033 }
2034